首先使用 X#(或 C#)的 EF 6 代码不会创建数据库

问题描述 投票:0回答:1

我正在努力使用 EF 6(针对 .NET 4.x)、代码优先和 SQLite。

我使用 X# 而不是 C#,但它只影响语法。

问题是未创建带有该表的 SQLite 数据库,因此

SaveChanges()
会抛出“DbUpdateException”异常,因为该表不存在(将使用 0 字节创建 db3 文件):

内部异常1: UpdateException:更新条目时发生错误。有关详细信息,请参阅内部异常。

内部异常2: SQLiteException:SQL逻辑错误
没有这样的表:博客

日志输出仅显示没有表

__MigrationHistory
但这应该不重要。

完整代码如下:

USING System
USING System.Collections.Generic
USING System.Linq
USING System.Data.Entity

PUBLIC CLASS CustomIntializer INHERIT CreateDatabaseIfNotExists<BloggingContext>
    
    PROTECTED OVERRIDE METHOD Seed(context AS BloggingContext) AS VOID
        VAR Blogs := List<Blog>{} {;
            Blog {} {Name := "Blog 1"},;
            Blog {} {Name := "Blog 2"};
        }
        Blogs:ForEach({b => context:Blogs:Add(b)})
        context:SaveChanges()
    END METHOD
END CLASS

PUBLIC CLASS Blog
    PUBLIC PROPERTY BlogId AS INT AUTO
    PUBLIC PROPERTY Name AS STRING AUTO
    PUBLIC VIRTUAL PROPERTY Posts AS List<Post> AUTO
END CLASS

PUBLIC CLASS Post
    PUBLIC PROPERTY PostId AS INT AUTO
    PUBLIC PROPERTY Title AS STRING AUTO
    PUBLIC PROPERTY Content AS STRING AUTO
    PUBLIC PROPERTY BlogId AS INT AUTO
    PUBLIC PROPERTY Blog AS Blog AUTO
END CLASS

PUBLIC CLASS BloggingContext INHERIT DbContext
    PUBLIC PROPERTY Blogs AS DbSet<Blog> AUTO
    PUBLIC PROPERTY Posts AS DbSet<Post> AUTO
    
    CONSTRUCTOR()
        SUPER("DataContext")
        SELF:Database:Log := Console.WriteLine

END CLASS

FUNCTION Start() AS VOID STRICT
    Database.SetInitializer<BloggingContext>(CustomIntializer{})
    BEGIN USING VAR db := BloggingContext{}
        db:database:Initialize(force := TRUE)
        db:Blogs.Add(Blog{} {Name := "Blog 1"})
        db:SaveChanges()
    END USING
    Console.WriteLine("*** Database updated ***")
    Console.ReadLine()

还有

app.config

<configuration>
    <configSections>
        <section name="entityFramework" 
                 type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" 
                 requirePermission="false" />
    </configSections>
    <entityFramework>
        <defaultConnectionFactory
            type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
        </defaultConnectionFactory>
        <providers>
            <provider invariantName="System.Data.SQLite" 
                      type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
        </providers>
    </entityFramework>
    <system.data>
        <DbProviderFactories>
            <remove invariant="System.Data.SQLite.EF6" />
            <add name="SQLite Data Provider (Entity Framework 6)"
                 invariant="System.Data.SQLite.EF6"
                 description=".NET Framework Data Provider for SQLite (Entity Framework 6)"
                 type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
            <remove invariant="System.Data.SQLite" />
            <add name="SQLite Data Provider"
                 invariant="System.Data.SQLite"
                 description=".NET Framework Data Provider for SQLite"
                 type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
        </DbProviderFactories>
    </system.data>
    <connectionStrings>
        <add name="DataContext"
             connectionString="Data Source=pemo.db3;Version=3"
             providerName="System.Data.SQLite.EF6" />
    </connectionStrings>
</configuration>

我错过了什么,或者 SQLite 的代码优先不适用于 EF 6?

c# .net sqlite entity-framework-6
1个回答
0
投票

解决方案是直接通过重写的 OnModelCreating() 方法中的 SQL 语句创建表,如下所示:

PROTECTED OVERRIDE METHOD OnModelCreating(modelBuilder As DbModelBuilder) As Void
    SELF:CreateTables()
    SELF:OnModelCreating(modelBuilder.Entity<TitleInfo>())
    SELF:OnModelCreating(modelBuilder.Entity<ArtistInfo>())
    SUPER.OnModelCreating(modelBuilder)
    RETURN

CreateTables() 方法完成所有工作:

/// <summary>
/// Create the tables of the database
/// </summary>
METHOD CreateTables() AS VOID
    VAR sqlText := "CREATE TABLE IF NOT EXISTS Titles (Id INTEGER PRIMARY KEY AUTOINCREMENT, Title TEXT NOT NULL, "
    sqlText += "ArtistID TEXT, Year INTEGER, Album TEXT, Length REAL, Rating INTEGER, Disco INTEGER,"
    sqlTExt += "AlbumCover BLOB, Remark TEXT);"
    VAR connectionString := Database:Connection:ConnectionString
    BEGIN USING VAR dbConnection := SQLiteConnection{connectionString}
        dbConnection:Open()
        BEGIN USING VAR dbCommand := dbConnection:CreateCommand()
            dbCommand:CommandText := sqlText
            dbCommand:ExecuteNonQuery()
        END USING
        sqlText := "CREATE TABLE IF NOT EXISTS Artists (Id TEXT PRIMARY KEY NOT NULL, Name TEXT NOT NULL);"
        BEGIN USING VAR dbCommand := dbConnection:CreateCommand()
            dbCommand:CommandText := sqlText
            dbCommand:ExecuteNonQuery()
        END USING
    END USING
    END METHOD

还有一点很重要,不要通过调用 SetInitializer() 方法来创建数据库文件:

// Don't create the database automatically
METHOD SetInitializeNoCreate() AS VOID
    Database:SetInitializer<MusicDbContext>(NULL)
END METHOD

并且基类构造函数不应使用命名参数但不带命名参数来调用:

Constructor()
    // Call the base class constructor with the connection string name
    // Don't use the name= for SQLite
    Super("80MusicCon") 

这样就创建了连接字符串中所述的 db3 数据库文件:

<connectionStrings>
  <add  
      name="80MusicCon"  
      connectionString="Data Source=./output/80musics.db3"  
      providerName="System.Data.SQLite" 
  />
</connectionStrings>

无需迁移。

虽然推荐的方法当然是使用Nuget包,但输出目录中所需的程序集是:

  • EntityFramework.dll
  • 系统.Data.Sqlite.dll
  • 系统.Data.SQLite.EF6.dll
  • SQLite.Interop.dll
© www.soinside.com 2019 - 2024. All rights reserved.