c# - EF6,如果没有 App.config,SQLite 将无法工作

标签 c# sqlite entity-framework-6

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

我发现这个答案看起来很有希望 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 提供程序的 Entity Framework 提供程序。确保提供程序已在应用程序配置文件的“entityFramework”部分中注册。参见 http://go.microsoft.com/fwlink/?LinkId=260882获取更多信息。

我已经为此苦苦思索了两天,但我的想法已经用完了。

最佳答案

使带有连接字符串的构造函数工作所需的最低限度是自定义 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 方法实现。

关于c# - EF6,如果没有 App.config,SQLite 将无法工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43615926/

相关文章:

android - 将 MYSQL 转换为适用于 Android 的 SQLITE 数据库

ef-code-first - Entity Framework 代码首先截断我的小数

c# - 了解 .NET 中的 ConfigurationManager

PHP 类可以在 PHP 上轻松使用 SQLite3?

c# - 如何在 C# 父类/接口(interface)和子类之间同步 XML 注释

ios - 如何在 iOS 应用程序中连接 FMDB 中两个不同数据库的两个表

entity-framework-6 - 在数据库优先方法中从数据库(EF6)更新模型时丢失可为空的属性

asp.net - Entity Framework 6 - 使用 select 的嵌套查询中的空值

c# - DataGridView 只读 "bug"

c# - 如何从 node.js 文件调用 C# dll 文件中的函数