前段时间试着用Entity Framework for Sqlite环境,发现了一些坑坑洼洼,记录一下。
同时试了一下配置多种数据库,包括Sqlite、Sql Server、Sql Server LocalDB、Sql Server Compact。
我建的demo项目结构以及通过NuGet安装的包:
EFDemo.MultipleDB.UI引用了EFDemo.MutipleDB项目。
1. 遇到的异常1
The Entity Framework provider type ‘System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6‘ registered in the application config file for the ADO.NET provider with invariant name ‘System.Data.SQLite.EF6‘ could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
我是是引用了Sqlite相关的dll了的(见下图),但是发现生成后再EFDemo.MultipleDB.UI下的生成文件中没有自动将这些dll拷贝过来。
2.
于是我将这些手动拷贝过来了。
2. 遇到的异常2
刚才的异常没了,又出现了一个异常。
The Entity Framework provider type ‘System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer‘ registered in the application config file for the ADO.NET provider with invariant name ‘System.Data.SqlClient‘ could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.
这次在代码里面加了这么一段,不用调用,只是在代码里让它存在:
/// <summary> /// 解决provider不能自动加载的问题 /// (不需要调用,放在这里即可) /// </summary> private static void FixProvidersNotAutoLoadProblem() { var _ = typeof(System.Data.SQLite.EF6.SQLiteProviderFactory); var __ = typeof(System.Data.Entity.SqlServer.SqlProviderServices); var ___ = typeof(System.Data.Entity.SqlServerCompact.SqlCeProviderServices); }
3. 遇到的异常3
使用了上面的方法,上面的那个异常没了,又一个新的来了。
Unable to determine the provider name for provider factory of type ‘System.Data.SQLite.SQLiteFactory‘. Make sure that the ADO.NET provider is installed or registered in the application config.
Sqlite的那些包是通过NuGet安装的,但是NuGet貌似没有帮忙生成完整的配置,所以需要自己补上。
这里贴上的是完整的,注意红色的是添加的:
<system.data> <DbProviderFactories> <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"/> <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.SqlServerCe.4.0" /> <add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" /> </DbProviderFactories> </system.data> <entityFramework> <defaultConnectionFactory type="System.Data.Entity.Infrastructure.SqlCeConnectionFactory, EntityFramework"> <parameters> <parameter value="System.Data.SqlServerCe.4.0" /> </parameters> </defaultConnectionFactory> <providers> <provider invariantName="System.Data.SQLite" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6" /> <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.SqlServerCe.4.0" type="System.Data.Entity.SqlServerCompact.SqlCeProviderServices, EntityFramework.SqlServerCompact" /> </providers> </entityFramework>
4. 虽然使用的是Code First,但是System.Data.SQLite.EF6是不能帮助我们自动生成数据库的表结构的,需要手动创建。(当然,可以找找有没有其他支持Sqlite的Migration的EF Provider)
OK了,到此这几个坑算是填平了。
5. 设置DataDirectory
我的Sqlite的连接字符串是这样写的:
<add name="BloggingContext_SQLite" connectionString="Data Source=|DataDirectory|\Blogging_SQLite.db" providerName="System.Data.SQLite.EF6"/>
为了开发方便,我将数据库文件放在了项目里面,这个样子:
怎样告诉连接字符串DataDirectory在这里呢?
private static void SetDataDir() { DirectoryInfo baseDir = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory); string data_dir = baseDir.FullName; if ((baseDir.Name.ToLower() == "debug" || baseDir.Name.ToLower() == "release") && (baseDir.Parent.Name.ToLower() == "bin")) { data_dir = Path.Combine(baseDir.Parent.Parent.FullName, "App_Data"); } AppDomain.CurrentDomain.SetData("DataDirectory", data_dir); }
在程序初始化时调用。
附: