使用 Entity Framework 6 和 SQLite 的问题

Posted

技术标签:

【中文标题】使用 Entity Framework 6 和 SQLite 的问题【英文标题】:Problems using Entity Framework 6 and SQLite 【发布时间】:2013-12-25 22:57:09 【问题描述】:

我正在尝试将实体框架与 SQLite 一起使用。我在将它集成到我的主应用程序时遇到了问题,所以我从头开始做了一个小测试,完全按照http://brice-lambson.blogspot.com/2012/10/entity-framework-on-sqlite.html 上的指示进行

说到底,运行项目时出现如下错误:

找不到 ADO.NET 提供程序的实体框架提供程序 不变名称“System.Data.SQLite”。确保提供者是 在应用程序配置的“entityFramework”部分注册 文件。更多信息请见http://go.microsoft.com/fwlink/?LinkId=260882 信息。

我的 app.config 如下所示:

<?xml version="1.0" encoding="utf-8"?>
<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>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
  <system.data>
    <DbProviderFactories>
      <add name="SQLite Data Provider"
            invariant="System.Data.SQLite"
            description="Data Provider for SQLite"
            type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
    </DbProviderFactories>
  </system.data>
  <connectionStrings>
    <add name="ChinookContext"
          connectionString=
"Data Source=|DataDirectory|Chinook_Sqlite_AutoIncrementPKs.sqlite"
          providerName="System.Data.SQLite" />
  </connectionStrings>
</configuration>

然后我看到了他关于 Entity Framework 6 的帖子。虽然这不是我得到的确切错误,但我尝试通过 NuGet 安装他更新的提供程序。错误消失了,但替换为这个:

无法加载文件或程序集'System.Data.SQLite.Linq, 版本=2.0.88.0,文化=中性,PublicKeyToken=db937bc2d44ff139' 或 它的依赖项之一。定位程序集的清单定义 与程序集引用不匹配。 (HRESULT 的例外情况: 0x80131040)

此外,我的 app.config (略微)更改为:

<?xml version="1.0" encoding="utf-8"?>
<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>
  <entityFramework>
    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
      <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.SQLiteProviderServices, System.Data.SQLite.Linq, Version=2.0.88.0, Culture=neutral, PublicKeyToken=db937bc2d44ff139" />
    </providers>
  </entityFramework>
  <system.data>
    <DbProviderFactories>
      <add name="SQLite Data Provider" invariant="System.Data.SQLite" description="Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
      <remove invariant="System.Data.SQLite" />
    </DbProviderFactories>
  </system.data>
  <connectionStrings>
    <add name="ChinookContext" connectionString="Data Source=|DataDirectory|Chinook_Sqlite_AutoIncrementPKs.sqlite" providerName="System.Data.SQLite" />
  </connectionStrings>
</configuration>

我已经尝试了我能想到的所有方法来解决这些错误,但没有任何效果。我尝试过使用其他 SQLite 二进制文件;我尝试手动编辑 SQLite 项目以使用 EF 版本 6;我已经更改了架构,一遍又一遍地添加和删除了 nuget 包,等等。

我不知道从这里去哪里。

【问题讨论】:

从提供者部分移除 System.Data.SQLite.Linq。 【参考方案1】:

只是想我会分享另一种在不使用app.config/web.config 的情况下使用 SQLite 配置 EF6 的方法。 EF6 现在支持此处on msdn 所述的基于代码的配置。我使用了以下代码(由于 Sly 已更新以消除反射):

public class SQLiteConfiguration : DbConfiguration

    public SQLiteConfiguration()
    
        SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
        SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
        SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
    

我使用它是为了在运行时注入正确的 DbContextDbProvider,并且不需要在主程序集中配置所有内容。

编辑:

作为Reyn said,如果您希望在web.config / app.config 文件中包含连接字符串,还需要为SQLite 添加IDbConnectionFactory。另一种方法是从DbContext 调用不同的基本构造函数,它传入一个新的SQLiteConnection 而不是连接字符串,如in this answer 所示。

【讨论】:

很好的答案。不过,SQLiteProviderServices 类是内部的,需要通过反射访问,这有点烦人。我查看了源代码,找到了一个替代方案: SetProviderServices( "System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService( typeof( DbProviderServices ) ) ); GetService() 调用返回 SQLiteProviderServices.Instance。 @Sly 谢谢你,这是一个很好的选择。 System.Data.SQLite 开发人员仍然是一个非常奇怪的设计决定。甚至对 GetService 的调用也会让您认为他们正在使用某种 DI/IoC,但实际上并非如此。 好帖子!你我的英雄! :-) 谢谢!【参考方案2】:

我知道这是一个老问题,但似乎没有人提供实际使用 .config 文件的答案。这是我的 web.config 的 system.data 和 entityframework 部分,它允许连接到 SQLServer 和 Sqlite 数据库:

<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>
  <entityFramework>
    <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" />
      <provider invariantName="System.Data.SQLite" 
          type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" />
    </providers>
  </entityFramework>

【讨论】:

这是 EF 6.1.3 和 Sqlite .net 库 1.0.102.0 的正确答案。 使用实体框架 6 和 Sqlite 的 nuget 包导致 .config 文件缺少第三个提供程序条目“System.Data.SQLite”。其余的都正确添加。不知道为什么会这样,但添加一行可以解决问题。【参考方案3】:

根据magicandre1981 的评论,我开始更仔细地研究提供程序节点的语法。我发现我的程序集与 type 属性中指定的版本不同,尽管我没有插入或触摸该特定行。通过删除强命名,我得到了 .Net 来加载库。作为参考,下面是新行:

<provider invariantName="System.Data.SQLite" type="System.Data.SQLite.SQLiteProviderServices, System.Data.SQLite.Linq" />

这让我重回正轨,我能够将我的结果与博客上的结果相匹配。

然而,我不得不指出,我认为 SQLite 不适合实体框架,因为缺少太多关键功能。我切换到通过 NuGet 安装的 SQL Server Compact Edition。对我的连接字符串进行简单的调整,我就可以使用 Entity Framework 的全部功能运行。与 SQLite 需要数小时的工作相比,它只花了不到一分钟的时间。如果可能,我建议切换数据库,System.Data.SQLite 还没有为实体框架做好准备。

【讨论】:

很好,但是您将如何将 SQL Server Compact 与您的应用程序一起分发?您将无法仅复制 dll 文件,您的用户必须在需要管理员权限的计算机上安装 SQL Server Compact... @DeanK。不一定,如果您跳过一些(不是无关紧要的箍),则可以进行基于副本的部署。有关详细信息,请参阅***.com/a/10800781/1163742。需要注意的一点是,Nuget 包似乎会为您收集 dll 和东西,并将它们放在适当的子目录中...... @Xcelled194 - 另外,这里有一个关于 SQLCE/EF6 私有部署的好教程:[link]。除了链接到我机器上 SQLCE 安装的 Private X86/AMD64 文件夹中的 6 个程序集和 3 个 VC++ 文件外,我能够做到这一点。我 ClickOnce 将它部署到没有安装 SQLCE 的干净 VM 上,它运行得很好。 我最近试过这个连接器。令人失望。当我明确指定使用 EF6 但仍需要使用 System.Data.SQLite 时,这令人困惑。更令人困惑的是,当它不是时,连接器会引发异常。让我想知道它在引擎盖下使用的是哪个版本。继续前进。 @Xcelled194,3 年后,在 Visual Studio 2017 中从 nugget 安装 SQLite 仍然很痛苦【参考方案4】:

对于任何使用基于代码的设置但仍然遇到相同异常的人:我需要在 kjbartel 的回答中另外设置连接工厂。

public class SQLiteConnectionFactory : IDbConnectionFactory

    public DbConnection CreateConnection(string nameOrConnectionString)
    
        return new SQLiteConnection(nameOrConnectionString);
    

然后在SQLiteConfiguration中设置默认的连接工厂

public class SQLiteConfiguration : DbConfiguration
        
    public SQLiteConfiguration()
    
        SetDefaultConnectionFactory(new SQLiteConnectionFactory());
        SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
        SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
        Type t = Type.GetType( "System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6");
        FieldInfo fi = t.GetField("Instance", BindingFlags.NonPublic | BindingFlags.Static);
        SetProviderServices("System.Data.SQLite", (DbProviderServices)fi.GetValue(null));
    

【讨论】:

以上是关于使用 Entity Framework 6 和 SQLite 的问题的主要内容,如果未能解决你的问题,请参考以下文章

不能在 Entity Framework 6.1.3 和 PostgreSQL 中使用打开的事务

Entity Framework 6 和 mysql TableDetails 强类型异常

Entity Framework 6 异步操作和 TranscationScope

《Entity Framework 6 Recipes》中文翻译系列 (13) -----第三章 查询之使用Entity SQL

Entity Framework 6 和 SQL Server CE,代码优先

Entity Framework 6 Code First 自定义函数