【问题标题】:EF6, SQLite won't work without App.configEF6,如果没有 App.config,SQLite 将无法工作
【发布时间】:2017-04-25 16:13:26
【问题描述】:

我正在尝试为无法更改 App.config 的应用程序制作一个使用 EF6.1 和 SQLite 的插件,因此需要在代码中设置所有配置和连接字符串。

我发现这个答案看起来很有希望Problems using Entity Framework 6 and SQLite

所以现在我有一个这样的配置类:

public class CollectionDbConfiguration : DbConfiguration
{
    public CollectionDbConfiguration()
    {
        SetProviderServices("System.Data.SQLite"(DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
        SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
        SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);                 
    }
}

我已经确认这在第一次创建上下文和所有这些返回值之前就被命中了。

我的上下文是这样的

public class MyContext : DbContext
{
    public MyContext(string connectionString)
    :   base(connectionString) { }

    public DbSet<MyEntity> MyEntities { get; set; }      
}

我有一些代码这样称呼它:

var context = new MyContext("Data Source = mytest.db; Version = 3;");
var entities = context.MyEntities.ToList();

当我尝试运行代码时,它看起来好像上下文假设连接字符串用于 SQL Server,因为它给了我:

不支持关键字:“版本”。

如果我删除它,我会收到一个错误,指出它无法连接并且它显然正在尝试连接到 SQL Server 数据库。

我尝试通过添加构造函数来传递 SQLite 连接:

public MyContext(DbConnection connection) 
    : base(connection, contextOwnsConnection: true)
{ }

然后用这个来调用它:

var context = new MyContext(new SQLiteConnection("Data Source = mytest.db; Version = 3;"));
var entities = context.MyEntities.ToList();

然后我得到错误:

无法确定类型为“System.Data.SQLite.SQLiteConnection”的连接的 DbProviderFactory 类型。确保在应用程序配置中安装或注册了 ADO.NET 提供程序。

所以我做了一个工厂解析器并注册了它

public class FactoryResolver : IDbProviderFactoryResolver
{
    public DbProviderFactory ResolveProviderFactory(DbConnection connection)
    {
        if (connection.GetType() == typeof(SQLiteConnection))
        {
            return SQLiteFactory.Instance;
        }

        if (connection.GetType() == typeof(EntityConnection))
        {
            return SQLiteProviderFactory.Instance;
        }

        return null;
    }
}

并补充:

SetProviderFactoryResolver(new FactoryResolver());

但现在我明白了:

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

我已经在这方面做了两天了,但我的想法已经不多了。

【问题讨论】:

    标签: c# sqlite entity-framework-6


    【解决方案1】:

    使带有连接字符串的构造函数工作的最低要求是自定义IProviderInvariantNameIDbDependencyResolverDbConfiguration

    public 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)) return SQLiteProviderInvariantName.Instance;
            if (type == typeof(DbProviderFactory)) return SQLiteProviderFactory.Instance;
            return SQLiteProviderFactory.Instance.GetService(type);
        }
    
        public IEnumerable<object> GetServices(Type type, object key)
        {
            var service = GetService(type, key);
            if (service != null) yield return service;
        }
    }
    
    class SQLiteDbConfiguration : DbConfiguration
    {
        public SQLiteDbConfiguration()
        {
            AddDependencyResolver(new SQLiteDbDependencyResolver());
        }
    }
    

    现在应该可以了:

    var context = new MyContext("Data Source = mytest.db; Version = 3;");
    var entities = context.MyEntities.ToList();
    

    更新:对于 NET4.0,您还需要自定义 IDbProviderFactoryResolver

    class SQLiteDbProviderFactoryResolver : IDbProviderFactoryResolver
    {
        public static readonly SQLiteDbProviderFactoryResolver Instance = new SQLiteDbProviderFactoryResolver();
        private SQLiteDbProviderFactoryResolver() { }
        public DbProviderFactory ResolveProviderFactory(DbConnection connection)
        {
            if (connection is SQLiteConnection) return SQLiteProviderFactory.Instance;
            if (connection is EntityConnection) return EntityProviderFactory.Instance;
            return null;
        }
    }
    

    并添加

    if (type == typeof(IDbProviderFactoryResolver)) return SQLiteDbProviderFactoryResolver.Instance;
    

    SQLiteDbDependencyResolver.GetService 方法实现。

    【讨论】:

    • 我试了一下,但现在我收到错误消息:无法确定类型为“System.Data.SQLite.SQLiteConnection”的连接的 DbProviderFactory 类型。确保在应用程序配置中安装或注册了 ADO.NET 提供程序。
    • 这很奇怪,因为我能够完全按照您描述的方式复制问题,然后上面的修复了它。确保项目中没有其他 DbConfiguration 类(例如,您在发布的代码中使用的类)和解析器 - 只是答案中的类。并且您将构造函数与连接字符串一起使用,而不是与连接一起使用。正如你所看到的,上面的IDbDependencyResolver蛮力解决了DbProviderFactory,所以不应该得到这样的错误。
    • 如果你能提供完整的repro项目,我可以看看,但我相信这是解决方案,因为我能够连接/使用SQLite数据库,明确注释掉与SQLite相关的来自 App.config 的实体,并保持 localdb 默认值、SqlServer 和 MySQL
    • 太棒了,成功了,谢谢。我尝试了一个自定义 IDbProviderFactoryResolver,但我没有为正确的 DbConnection 类型返回正确的类型,所以它失败了。
    • 不客气。重现项目帮助很大 - 我的测试(NET4.6)使用DefaultDbProviderFactoryResolver 和你的 - Net40DefaultDbProviderFactoryResolver 似乎使用不同的代码路径 - 前者仅使用 connection.ProviderFactory 和后者 - 配置文件:(跨度>
    猜你喜欢
    • 1970-01-01
    • 2021-03-29
    • 2015-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多