使用Entity Framework 6和SQLite时遇到的问题

47

我正试图使用Entity Framework与SQLite。在将它集成到我的主应用程序时遇到了问题,因此我从头开始进行了一项小测试,完全按照http://brice-lambson.blogspot.com/2012/10/entity-framework-on-sqlite.html上的指示进行。

最终,当运行该项目时,我收到以下错误:

  

未找到带有不变名称'System.Data.SQLite'的ADO.NET提供程序的Entity Framework提供程序。确保该提供程序已在应用程序配置文件的“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, Version=2.0.88.0, Culture=neutral, 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包等等。

我不知道接下来该怎么做。


3
请将 "System.Data.SQLite.Linq" 从提供程序部分移除。 - magicandre1981
4个回答

64

我想分享一种无需使用app.config/web.config的方式配置EF6与SQLite的方法。EF6现在支持基于代码的配置,如此处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)));
    }
}

我使用这个方法是为了在运行时注入正确的DbContext,因此不需要在主程序集中配置所有内容而且可以使用DbProvider

编辑:

Reyn所说,如果您希望在web.config/app.config文件中使用连接字符串,则还需要添加一个SQLite的IDbConnectionFactory。另一种方法是从您的DbContext中调用一个不同的基类构造函数,而不是连接字符串,传递一个新的SQLiteConnection,如此答案中所示


2
很好的答案。不过,SQLiteProviderServices类是内部的,需要通过反射访问,有点烦人。我查看了源代码,并找到了一种替代方法:SetProviderServices("System.Data.SQLite",(DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));GetService()调用返回SQLiteProviderServices.Instance。 - Sly
@Sly 谢谢你的指出,这是一个很好的发现。System.Data.SQLite开发人员的设计决策确实非常奇怪。甚至对GetService的调用让人以为他们在使用某种依赖注入/控制反转,但实际上并不是这样。 - kjbartel
很棒的帖子!你是我的英雄!:-) 谢谢! - HaGever

33

我知道这是一个老问题,但似乎没有人提供了一个真正使用.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下的正确答案。 - ZZZ
使用Entity Framework 6和Sqlite的Nuget包会导致.config文件缺少第三个提供程序条目"System.Data.SQLite"。其余部分都已正确添加。不确定为什么会出现这种情况,但添加一行代码即可解决问题。 - denver

23

根据magicandre1981的评论,我开始更仔细地查看提供程序节点的语法。我发现我的汇编版本与type属性中指定的版本不同,尽管我没有插入或触摸那一行。通过删除强命名,我使得.Net能够加载该库。以下是新的那一行:

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

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

但是,我不得不指出,我已经决定SQLite并不适合Entity Framework,因为缺少太多关键功能。我转向了SQL Server Compact Edition,通过NuGet安装它。只需要简单调整我的连接字符串,我就可以使用完整的Entity Framework功能。相比于耗费数小时的SQLite,这只用了不到一分钟。如果可能的话,我建议切换数据库,System.Data.SQLite还没有准备好支持Entity Framework。


1
不错,但是你将如何分发SQL Server Compact与你的应用程序?你不能只复制dll文件,你的用户将需要在其计算机上安装SQL Server Compact并需要管理员权限... - Dean Kuga
@DeanK。不一定,如果你跳过了一些(不可忽略的)障碍,就可以进行基于复制的部署。有关详细信息,请参见https://dev59.com/K2gv5IYBdhLWcg3wQ-gU#10800781。需要注意的一点是,Nuget包似乎会为您收集dll和其他文件,并将它们放置在适当的子目录中... - Xcelled
@Xcelled194 - 这里还有一个关于SQLCE/EF6私有部署的好教程:[链接]。我能够在没有任何其他东西的情况下完成这个操作,只需链接到SQLCE安装程序中的Private X86/AMD64文件夹中的6个程序集和3个VC++文件即可。我将其ClickOnce部署到一个没有安装SQLCE的干净虚拟机上,它运行得非常好。 - InteXX
@CandyChiu:我发现这是由于DefaultConnectionFactory引起的。必须像这里https://stackoverflow.com/questions/19025177/system-data-sqlite-entity-framework-code-first-programmatic-providername-specifi中所示手动更改它。 - Roman Plášil
1
@Xcelled194,三年后,在Visual Studio 2017中从NuGet安装SQLite仍然很痛苦。 - Buda Florin
显示剩余6条评论

18

如果您正在使用基于代码的设置,但仍然遇到相同的异常:我需要按照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));
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接