Я пытаюсь сделать подключаемый модуль, который будет использовать 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.
У меня есть свечка на этом уже два дня, и у меня заканчиваются идеи.
Минимальным, необходимым для создания конструктора со строкой соединения является пользовательский 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
.
DbConfiguration
(например, того, который вы использовали в размещенном коде) и преобразователей - только классы из ответа. И что вы используете конструктор со строкой соединения, а не со связью. Как вы можете видеть, приведенная выше грубая силаIDbDependencyResolver
разрешаетDbProviderFactory
, поэтому не должно быть такой ошибки.