EF6, SQLite не будет работать без App.config

14

Я пытаюсь сделать подключаемый модуль, который будет использовать EF6.1 и SQLite для приложения, где я не могу изменить App.config, поэтому вся строка конфигурации и подключения должна быть установлена ​​в коде.

Я нашел этот ответ, который выглядел многообещающим Проблемы с использованием Entity Framework 6 и 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, поскольку она дает мне:

Ключевое слово не поддерживается: 'version'.

Если я удалю его, я получаю сообщение об ошибке, которое он не может подключить, и его явное стремление подключиться к базе данных 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();

Но тогда я получаю ошибку:

Невозможно определить тип DbProviderFactory для подключения типа "System.Data.SQLite.SQLiteConnection". Убедитесь, что поставщик ADO.NET установлен или зарегистрирован в конфигурации приложения.

Итак, я создал распознаватель factory и зарегистрировал, что

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());

но теперь я получаю следующее:

Поставщик ADO.NET не найден провайдер Entity Framework с инвариантным именем "System.Data.SQLite.EF6". Убедитесь, что провайдер зарегистрирован в разделе "entityFramework" файла конфигурации приложения. Подробнее см. http://go.microsoft.com/fwlink/?LinkId=260882.

У меня есть свечка на этом уже два дня, и у меня заканчиваются идеи.

Теги:
entity-framework-6

1 ответ

12
Лучший ответ

Минимальным, необходимым для создания конструктора со строкой соединения является пользовательский IProviderInvariantName, IDbDependencyResolver и DbConfiguration:

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.

  • 0
    Я попробовал, но теперь получаю сообщение об ошибке: Невозможно определить тип DbProviderFactory для соединения типа «System.Data.SQLite.SQLiteConnection». Убедитесь, что поставщик ADO.NET установлен или зарегистрирован в конфигурации приложения.
  • 0
    Это странно, потому что я смог продублировать проблему в точности так, как вы ее описали, а затем все исправлено выше. Убедитесь, что в проекте нет других классов DbConfiguration (например, того, который вы использовали в размещенном коде) и преобразователей - только классы из ответа. И что вы используете конструктор со строкой соединения, а не со связью. Как вы можете видеть, приведенная выше грубая сила IDbDependencyResolver разрешает DbProviderFactory , поэтому не должно быть такой ошибки.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню