简体   繁体   English

带有实体框架 6 的 SQLite“没有这样的表”

[英]SQLite with Entity Framework 6 “no such table”

I'm trying to implement this question with SQLite and EntityFramework 6 code first.我试图首先用SQLiteEntityFramework 6代码来实现这个问题 I can create the database and there is a file (although empty), but when I try to add an entry to the database it says there is no such table.我可以创建数据库并且有一个文件(虽然是空的),但是当我尝试向数据库添加一个条目时,它说没有这样的表。 Yet, when I try to create the table manually ( db.Database.ExecuteSqlCommand("CREATE TABLE etc.) ) it tells me that the table already exists.然而,当我尝试手动创建表( db.Database.ExecuteSqlCommand("CREATE TABLE etc.) )时,它告诉我该表已经存在。

I found some questions about this already, but they're all about the path not being absolute, which is simply not the case here.我已经发现了一些关于此的问题,但它们都是关于路径不是绝对的,这里的情况并非如此。

Context语境

//Context:
class MediaContext : DbContext
{
    public DbSet<MediaModel> Media { get; set; }

    public MediaContext(string filename): base(new SQLiteConnection() {
        ConnectionString =
            new SQLiteConnectionStringBuilder()
            { DataSource = filename, ForeignKeys = false }
            .ConnectionString
    }, true)
    {

    }        
}

DAL达尔文

//In the DAL:
public DataAccessLayer(string path)
{
   _path = Path.GetFullPath(path); //<--The path already comes full in, I'm just paranoid at this point.
   _connectionPath = _path + @"\MyDatabase.sqlite";

   using (var db = new MediaContext(_connectionPath))
   {
      db.Database.CreateIfNotExists();
      db.Database.Initialize(false);                

       db.SaveChanges();
   }

   public void Generate()
   {
       using (var db = new MediaContext(_connectionPath))
       {
          db.Media.Add(new MediaModel("test"));
          db.SaveChanges(); //<--SQLiteException: SQL logic error or missing database: no such table: MediaModels

        }
    }

App.Config应用程序配置

//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" />
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
      <parameters>
        <parameter value="v13.0" />
      </parameters>
    </defaultConnectionFactory>
    <providers>
      <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </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.EF6" />
      <add name="SQLite Data Provider" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
    </DbProviderFactories>
  </system.data>
</configuration>

I have got Code First approach working inspired by this post:受这篇文章的启发,我得到了 Code First 方法的启发:
Create SQLite DB using Entity Framework Core Code First 首先使用 Entity Framework Core Code 创建 SQLite DB

The trick is to have a call to EnsureCreated in the context constructor:诀窍是在上下文构造函数中调用确保创建:

    public MediaContext()
    {
        Database.EnsureCreated();
    }

Regarding the table name to property name matching:关于表名到属性名匹配:
You can use the Table attribute to make things work:您可以使用Table属性来使事情工作:

public DbSet<MediaModel> Media { get; set; }

and explicitly specify the table name in your model class although this seems redundant:并在您的模型类中明确指定表名,尽管这似乎是多余的:

[Table("MediaModel")]
public class MediaModel

EF6 的 SQLite 提供程序不支持 Code First/Migrations 工作流,因此您必须在 EF6 工作流之外手动创建数据库。

This is the recommended reply from Microsoft itself :这是微软自己推荐的回复:

Visual Studio uses an inconsistent working directory when running .NET Core console apps. Visual Studio 在运行 .NET Core 控制台应用程序时使用不一致的工作目录。 (see dotnet/project-system#3619) This results in an exception being thrown: no such table: Blogs. (请参阅 dotnet/project-system#3619)这会导致抛出异常: no such table: Blogs. To update the working directory:要更新工作目录:

Right-click on the project and select Edit Project File右键单击项目并选择编辑项目文件

Just below the TargetFramework property, add the following:在 TargetFramework 属性下方,添加以下内容:

<StartWorkingDirectory>$(MSBuildProjectDirectory)</StartWorkingDirectory>

Save the file保存文件

Now you can run the app:现在您可以运行该应用程序:

Debug > Start Without Debugging调试 > 在不调试的情况下启动

Like ErikEJ said does SQLite not support code first in they way I use it, and apparently it has a strict naming policy.就像 ErikEJ 所说的那样,SQLite 不以我使用它的方式首先支持代码,而且显然它有严格的命名策略。

To make it all work I had to manually create the table, and adapt the context to the naming schema ( Media => MediaModels ).为了使这一切正常工作,我必须手动创建表,并使上下文适应命名模式( Media => MediaModels )。

Context语境

public DbSet<MediaModel> MediaModels { get; set; }

DAL达尔文

public DataAccessLayer(string path)
{
    _path = Path.GetFullPath(path);
    _connectionPath = _path + @"\MyDatabase.sqlite";
    
    using (var db = new MediaContext(_connectionPath))
    {
        db.Database.ExecuteSqlCommand("CREATE TABLE IF NOT EXISTS 'MediaModels' ('Name' TEXT, 'FilePath' TEXT NOT NULL PRIMARY KEY, 'Tags' TEXT, 'Note' TEXT, 'FileExtension' TEXT)");

        db.SaveChanges();
    }
}
    
public void Generate()
{
    using (var db = new MediaContext(_connectionPath))
    {
        db.MediaModels.Add(new MediaModel("test"));
        db.SaveChanges();
    }
}

That code is still not perfect, and I'll try to update this answer as I improve it.该代码仍然不完美,我会在改进它时尝试更新此答案。

I'm using .NET Core and EntityFramework Core 2 and code first migration for SQLite.我正在使用 .NET Core 和 EntityFramework Core 2 并为 SQLite 进行代码优先迁移。 Specifying table name in OnModelCreating helped to solve the issue:OnModelCreating指定表名有助于解决问题:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<File>()
            .ToTable(typeof(File).Name + "s") // <-- the argument could be just "Files"
            .HasKey(lf => new { lf.MachineName, lf.PathName });

        base.OnModelCreating(modelBuilder);
    }

Another option - TableAttribute also should have helped:另一个选项 - TableAttribute也应该有帮助:

    [Table("Files")]
    public class File
    {
        // ...
    }

OnModelCreating will override table name specified in TableAttribute if both are specified.如果两者都被指定, OnModelCreating将覆盖TableAttribute中指定的表名。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM