【问题标题】:SQLite in class library. DB-Provider not found类库中的 SQLite。未找到 DB-Provider
【发布时间】:2019-01-31 04:07:15
【问题描述】:

我们有一个类库来处理所有与 DB 相关的操作。 (SQLite 和 MSSQL)我试图摆脱可执行项目中的所有提供程序和工厂 (with this approach),因为类库已经在 App.config 中包含 DB-Configuration。

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

  <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" />
    </DbProviderFactories>
  </system.data>

然而,虽然 MSSQL 目前运行良好,但 SQLite 会引发异常:

如果我将提供程序添加到可执行文件中的 App.config,它确实有效。但这是我试图避免的。这个问题有解决办法吗?

【问题讨论】:

    标签: c# entity-framework sqlite class-library


    【解决方案1】:

    为了支持不带 app.config 的 EF6 数据库提供程序,您通常需要 DbConfiguration 派生类,该派生类分别使用 SetProviderFactorySetProviderServices 方法注册适当的 DbProviderFactoryDbProviderServices

    但是,这对于 SQLite 提供程序来说还不够,因为它没有实现导致相关运行时异常的 IProviderInvariantName 服务。因此,您需要通过通过AddDependencyResolver 方法注册的自定义IDbDependencyResolver 添加该服务的实现。

    假设您的类库项目引用了System.Data.SQLiteSystem.Data.SQLite.EF6 程序集,并且连接字符串使用"System.Data.SQLite.EF6" 作为providerName,则将以下实现类添加到类库项目中:

    using System.Data.Entity.Infrastructure;
    using System.Data.Entity.Infrastructure.DependencyResolution;
    using System.Data.SQLite.EF6;
    using System.Data.SQLite;
    
    class SQLiteProviderInvariantName : IProviderInvariantName
    {
        public static readonly SQLiteProviderInvariantName Instance = new SQLiteProviderInvariantName();
        private SQLiteProviderInvariantName() { }
        public const string ProviderName = "System.Data.SQLite.EF6";
        public string Name { get { return ProviderName; } }
    }
    
    class SQLiteDbDependencyResolver : IDbDependencyResolver
    {
        public object GetService(Type type, object key)
        {
            if (type == typeof(IProviderInvariantName))
            {
                if (key is SQLiteProviderFactory || key is SQLiteFactory)
                    return SQLiteProviderInvariantName.Instance;
            }
            return null;
        }
    
        public IEnumerable<object> GetServices(Type type, object key)
        {
            var service = GetService(type, key);
            if (service != null) yield return service;
        }
    }
    

    然后将以下配置类(如果您已经有,则更新现有配置类)再次添加到包含您的上下文类的类库项目中:

    using System.Data.Entity;
    using System.Data.Entity.Core.Common;
    using System.Data.SQLite.EF6;
    
    class MyDbConfiguration : DbConfiguration
    {
        public MyDbConfiguration()
        {
            SetProviderFactory(SQLiteProviderInvariantName.ProviderName, SQLiteProviderFactory.Instance);
            SetProviderServices(SQLiteProviderInvariantName.ProviderName, (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
            AddDependencyResolver(new SQLiteDbDependencyResolver());
        }
    }
    

    仅此而已。您可以从类库项目中删除 app.config,并且可以从可执行的 app.config 中使用这样的连接字符串:

    <add name="MyDb_SQLite" providerName="System.Data.SQLite.EF6" connectionString="Data Source =|DataDirectory|MyDb.sqlite" />
    

    有关详细信息,请参阅Code-based configuration 和 EF6 文档的相关主题。请注意,类库不是应用程序,所以应用程序配置文件实际上是可执行配置文件。无法使用您的类库配置文件强制 EF6,因此基于代码的配置和可执行配置文件是唯一的选项。

    【讨论】:

    • 但这正是我不想做的。我想摆脱可执行文件中的配置文件。
    • 您不需要任何配置文件 - 上面的代码配置将为您完成。但是您在某处命名了连接字符串(以指定提供程序名称),对吗?他们目前位于哪里?我猜不可能在图书馆项目中。
    • 确实如此。它们在可执行文件中。但是,可执行文件使用连接字符串从库中调用 DAL。因此,可执行文件中不应需要提供者信息。此外,连接字符串以非典型方式存储。 (自己的XML结构)
    • 所以我们很好。没有供应商信息,没有工厂信息。在可执行的 app.config 中没有 &lt;entityFramework&gt;,没有 &lt;DbProviderFactories&gt;,只有 &lt;connectionStrings&gt;。我在这里EF6, SQLite won't work without App.config 已经有类似的工作解决方案,只是它仅适用于 SQLite,而上述适用于 SQLite 和 SqlServer。
    • “魔法”由MyDbConfiguration 类提供。 EF6 在包含 db 上下文(在您的情况下为类库项目)的程序集中搜索派生自 DbConfiguration 的类并自动实例化它们,因此构造函数调用在运行时注册了必要的信息,从而有效地消除了对配置文件的需要为了那个原因。我认为从解决方案的解释中可以清楚地看到这一点(否则就没有意义了)。只需将以上 3 个类添加到您的类库中,您就会看到。
    猜你喜欢
    • 1970-01-01
    • 2021-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-10
    • 2014-06-16
    • 2023-03-16
    相关资源
    最近更新 更多