Добавьте DbProviderFactory без App.Config
Я использую DbProviderFactories в своем слое данных (на основе Entity Framework), и я использую SQLite для своей базы данных, но мне не нужно, чтобы App.Config имел следующий код:
<configuration>
<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" />
</DbProviderFactories>
</system.data>
</configuration>
Вместо этого я хотел бы, чтобы мой слой данных помещал это программно. Кто-нибудь знает способ сделать это?
EDIT:
Причиной этого является то, что я использую контейнер IoC для выбора уровня данных, а некоторые из моих слоев данных не нуждаются в значениях App.Config или их трудно привязать к слою данных.
Ответы
Ответ 1
Следующие, вероятно, вызовут солнечные пятна и свергут западную цивилизацию. Это может даже вызвать дискуссию о программировании канальной ленты (заставьте ее остановиться!), Но она работает (пока)
try
{
var dataSet = ConfigurationManager.GetSection("system.data") as System.Data.DataSet;
dataSet.Tables[0].Rows.Add("SQLite Data Provider"
, ".Net Framework Data Provider for SQLite"
, "System.Data.SQLite"
, "System.Data.SQLite.SQLiteFactory, System.Data.SQLite");
}
catch (System.Data.ConstraintException) { }
Ответ 2
JoshRivers выше разместил решение для SQLite. На самом деле это можно использовать и для других адаптеров - я смог заставить его работать в MySQL, используя его пример. Я завернул это в нечто более общее. Это должно запускаться после запуска приложения и для .NET-коннектора версии 6.6.5.0 (но я думаю, что это хорошо для других версий.)
string dataProvider = @"MySql.Data.MySqlClient";
string dataProviderDescription = @".Net Framework Data Provider for MySQL";
string dataProviderName = @"MySQL Data Provider";
string dataProviderType = @"MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.6.5.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d";
bool addProvider = true;
var dataSet = ConfigurationManager.GetSection("system.data") as DataSet;
foreach (DataRow row in dataSet.Tables[0].Rows)
{
if ((row["InvariantName"] as string) == dataProvider)
{
// it is already in the config, no need to add.
addProvider = false;
break;
}
}
if (addProvider)
dataSet.Tables[0].Rows.Add(dataProviderName, dataProviderDescription, dataProvider, dataProviderType);
Ответ 3
ПОСЛЕДНИЙ ОТВЕТ:
Вы всегда можете напрямую получить factory следующим образом:
DbProviderFactory factory = System.Data.SQLite.SQLiteFactory.Instance;
// (note that the rest of the code is still provider-agnostic.)
Или используйте контейнер IoC для разрешения DbProviderFactory
, например:
container.RegisterInstance<DbProviderFactory>(SQLiteFactory.Instance);
Я предпочитаю не использовать DbProviderFactories.GetFactory
из-за ограничения использования файла конфигурации (или взлома, как в @JoshRiver answer).
Все DbProviderFactories.GetFactory
есть, он просматривает зарегистрированное имя с именем сборки factory, используя имя провайдера, а затем получает значение статического свойства Instance
с помощью отражения.
Если вы не хотите использовать конфигурацию, один из вышеперечисленных методов может быть более удобным в зависимости от вашего варианта использования.
Ответ 4
Обновление для EF 6.0 +
Вы можете добавить DbProviderFactory
, зарегистрировав IDbDependencyResolver
и разрешив тип DbProviderFactory
. Пример этого ниже:
static class Program
{
[STAThread]
static void Main()
{
System.Data.Entity.DbConfiguration.Loaded += (_, a) => {
a.AddDependencyResolver(new MyDependencyResolver(), true);
};
Application.Run(new Form1());
}
}
class MyDependencyResolver : System.Data.Entity.Infrastructure.DependencyResolution.IDbDependencyResolver {
public object GetService(Type type, object key) {
// Output the service attempting to be resolved along with it key
System.Diagnostics.Debug.WriteLine(string.Format("MyDependencyResolver.GetService({0}, {1})", type.Name, key == null ? "" : key.ToString()));
if (type == typeof(System.Data.Common.DbProviderFactory)) {
// Return whatever DbProviderFactory is relevant
return new MyDbProviderFactory();
}else if(type == typeof(System.Data.Entity.Infrastructure.IProviderInvariantName) && key != null && key == "MyDbProviderFactory"){
// Return the Provider invariant name for the MyDbProviderFactory
return new MyProviderInvariantName();
}
return null;
}
public IEnumerable<object> GetServices(Type type, object key) {
return new object[] { GetService(type, key) }.ToList().Where(o => o != null);
}
}
возможно, вам придется решать и некоторые дополнительные типы, в зависимости от того, какой тип переопределения вам нужно сделать и как настроен ваш проект. В основном просто начинайте с кода выше и продолжайте отлаживать, пока не определите все службы, которые вам нужны для решения, с учетом ваших конкретных требований.
Подробнее о разрешении зависимостей EF вы можете узнать по ссылкам ниже:
Кроме того, вы можете сделать эту конфигурацию, переопределив DbConfiguration
, как описано в первой ссылке выше.
Ответ 5
Выбор провайдера БД factory программно в значительной степени поражает цель. Вы могли бы также использовать классы, специфичные для SQLite, вместо всех этих интерфейсов, нет?
Ответ 6
см. следующий фрагмент
public DataProviderManager(string ProviderName)
{
var _Provider = DbProviderFactories.GetFactory(ProviderName);
}
вам необходимо передать имя ProviderName, которое в вашем случае - "System.Data.SQLite".
вам не нужно создавать раздел конфигурации приложения. Этот раздел создается SQLite в machine.config после установки поставщика SQLite.net.
вся цель раздела appconfig - помочь вам получить список настроенных провайдеров .net при вызове следующей команды:
public GetProvidersList()
{ Таблица DataTable = DbProviderFactories.GetFactoryClasses();
}
Ответ 7
Еще более поздний ответ
Получите его, используя конфигурацию, как указано выше. Я обнаружил, что это, по-видимому, требует, чтобы сборка поставщика была где-то, в которой запущенная программа может ее найти.
/// <summary>
/// Creates a DbProviderFactory instance without needing configuration file
/// </summary>
/// <param name="lsProviderName">Name of the provider. Like "System.Data.SQLite"</param>
/// <param name="lsClass">Class and assembly information. Like "System.Data.SQLite.SQLiteFactory, System.Data.SQLite"</param>
/// <returns>A specific DbProviderFactory instance, or null if one can't be found</returns>
protected static DbProviderFactory GetDbProviderFactoryFromConfigRow(string lsProviderName, string lsClass)
{
if (string.Empty != lsProviderName && string.Empty != lsClass)
{
DataRow loConfig = null;
DataSet loDataSet = ConfigurationManager.GetSection("system.data") as DataSet;
foreach (DataRow loRow in loDataSet.Tables[0].Rows)
{
if ((loRow["InvariantName"] as string) == lsProviderName)
{
loConfig = loRow;
}
}
if (null == loConfig)
{
loConfig = loDataSet.Tables[0].NewRow();
loConfig["InvariantName"] = lsProviderName;
loConfig["Description"] = "Dynamically added";
loConfig["Name"] = lsProviderName + "Name";
loConfig["AssemblyQualifiedName"] = lsClass;
loDataSet.Tables[0].Rows.Add(loConfig);
}
try
{
DbProviderFactory loDbProviderFactoryByRow = DbProviderFactories.GetFactory(loConfig);
return loDbProviderFactoryByRow;
}
catch (Exception loE)
{
//// Handled exception if needed, otherwise, null is returned and another method can be tried.
}
}
Другой метод, который получает поле Instance непосредственно из сборки. Он работает даже тогда, когда DLL находится где-то в системе.
/// <summary>
/// Creates a DbProviderFactory instance without needing configuration file
/// </summary>
/// <param name="lsClass">Class and assembly information. Like "System.Data.SQLite.SQLiteFactory, System.Data.SQLite"</param>
/// <param name="lsAssemblyFile">Full path to the assembly DLL. Like "c:\references\System.Data.SQLite.dll"</param>
/// <returns>A specific DbProviderFactory instance, or null if one can't be found</returns>
protected static DbProviderFactory GetDbProviderFactoryFromAssembly(string lsClass, string lsAssemblyFile)
{
if (lsAssemblyFile != string.Empty && lsClass != string.Empty)
{
Assembly loAssembly = System.Reflection.Assembly.LoadFrom(lsAssemblyFile);
if (null != loAssembly)
{
string[] laAssembly = lsClass.Split(new char[] { ',' });
Type loType = loAssembly.GetType(laAssembly[0].Trim());
FieldInfo loInfo = loType.GetField("Instance");
if (null != loInfo)
{
object loInstance = loInfo.GetValue(null);
if (null != loInstance)
{
if (loInstance is System.Data.Common.DbProviderFactory)
{
return loInstance as DbProviderFactory;
}
}
}
}
}
return null;
}
Ответ 8
В .NET Core 2.1 и более поздних версиях вы можете использовать DbProviderFactories.RegisterFactory
для программной регистрации DbProviderFactory
.
Ответ 9
См. здесь примеры: MSDN: получение DbProviderFactory