EF6 SQLite插件开发遇配置错误:默认DbConfiguration提前加载求助
问题背景
开发插件时采用EF6+SQLite组合,用户反馈遇到如下错误:
The default DbConfiguration instance was used before the 'SQLiteConfiguration' type was discovered
已为Context添加[DbConfigurationType(typeof(SQLiteConfiguration))]特性,但问题未解决,推测与用户同时加载其他插件有关。同时存在两个疑问:
- 是否需要自行实现
MyProviderServices和MyConnectionFactory,还是System.Data.SQLite库已提供这些组件? - 如何修改
SQLiteConfiguration构造函数,是否需要保留SetProviderFactory和SetProviderServices代码?
现有代码
Context与Configuration代码
[DbConfigurationType(typeof(SQLiteConfiguration))] public class Context : DbContext { public Context() : base( new SQLiteConnection { ConnectionString = "some_connection_string"}, true) { } public DbSet<Foo> Foos{ get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { var sqliteConnectionInitializer = new SqliteDropCreateDatabaseWhenModelChanges<Context>(modelBuilder); System.Data.Entity.Database.SetInitializer(sqliteConnectionInitializer); } } 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))); } }
自动生成的app.config
<?xml version="1.0" encoding="utf-8"?> <configuration> <configSections> <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --> <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/> </configSections> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/> <bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1"/> </dependentAssembly> <dependentAssembly> <assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/> <bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1"/> </dependentAssembly> </assemblyBinding> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <dependentAssembly> <assemblyIdentity name="System.Data.SQLite" culture="neutral" publicKeyToken="db937bc2d44ff139" /> <bindingRedirect oldVersion="0.0.0.0-1.0.117.0" newVersion="1.0.117.0"/> </dependentAssembly> </assemblyBinding> </runtime> <entityFramework> <providers> <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"/> <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> </configuration>
疑问解答与修复方案
疑问1:是否需要自行实现ProviderServices和ConnectionFactory?
不需要。System.Data.SQLite.EF6库已提供现成的SQLiteProviderFactory(内含DbProviderServices实现)和SQLiteConnectionFactory,直接使用即可,无需自行编写。
疑问2:SQLiteConfiguration构造函数的修改建议
现有配置代码逻辑正确,但需确保自定义配置被EF6提前加载,避免默认配置先初始化。可做以下调整:
- 保持
SQLiteConfiguration为public且带无参数构造函数(当前代码已满足); - 可在插件加载的早期(创建Context之前)主动初始化配置:
// 插件初始化阶段执行 DbConfiguration.SetConfiguration(new SQLiteConfiguration());
- 必须保留
SetProviderFactory和SetProviderServices代码,这是EF6识别SQLite提供程序的核心配置。
核心错误修复:解决默认配置先加载问题
错误根源是EF6在自定义配置被发现前已初始化默认配置,多插件环境下其他插件可能提前触发EF6初始化。可通过以下方案解决:
方案1:在app.config中添加SQLite提供程序配置
在entityFramework节点下补充SQLite提供程序,确保EF6启动时直接识别:
<entityFramework> <providers> <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/> <!-- 添加该行 --> <provider invariantName="System.Data.SQLite.EF6" type="System.Data.SQLite.EF6.SQLiteProviderServices, System.Data.SQLite.EF6"/> </providers> </entityFramework>
方案2:提前主动设置自定义配置
在插件加载的最早阶段(未创建任何Context前)执行配置设置,抢占EF6初始化时机:
// 插件初始化入口调用 DbConfiguration.SetConfiguration(new SQLiteConfiguration());
方案3:避免提前触发EF6操作
检查插件代码,确保所有EF6相关操作(如Database.Exists())都在自定义配置设置之后执行,防止提前触发默认配置初始化。
方案4:代码注册DbProviderFactory避免配置冲突
将DbProviderFactories的配置移到代码中,规避多插件间的配置覆盖问题,在SQLiteConfiguration构造函数中添加:
var factory = SQLiteProviderFactory.Instance; if (DbProviderFactories.GetFactoryClasses().All(f => f.InvariantName != "System.Data.SQLite.EF6")) { DbProviderFactories.RegisterFactory("System.Data.SQLite.EF6", factory); }
内容的提问来源于stack exchange,提问作者emilaz

