我在我的数据层(基于实体框架)中使用DbProviderFactories并且正在使用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>
相反,我想让我的数据层以编程方式放入。有人知道这样做的方法吗?
编辑:
这样做的原因是我使用IoC容器来选择数据层,而我的一些数据层不需要App.Config值,或者让它们与数据层紧密相连。
答案 0 :(得分:52)
以下可能会导致太阳黑子并推翻西方文明。它甚至可能引发关于风管磁带编程的讨论(让它停止!),但它可以工作(现在)
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) { }
答案 1 :(得分:5)
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);
答案 2 :(得分:3)
迟到的答案:
你总是可以直接找到这样的工厂:
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's answer中的hack)的限制。
所有DbProviderFactories.GetFactory
都是,它使用提供程序名称查找工厂类型的已注册程序集限定名称,然后获取静态{{1}的值使用反射的属性。
如果您不想使用配置,根据您的使用情况,上述方法之一可能会更方便。
答案 3 :(得分:3)
您可以通过注册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's 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's 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
来执行此配置,如上面第一个链接中所述。答案 4 :(得分:2)
以编程方式选择数据库提供程序工厂几乎失败了目的。您也可以使用特定于SQLite的类而不是所有这些接口,不是吗?
答案 5 :(得分:0)
请参阅以下代码段
public DataProviderManager(string ProviderName)
{
var _Provider = DbProviderFactories.GetFactory(ProviderName);
}
您需要传递在您的情况下为“System.Data.SQLite”的ProviderName。
您无需创建应用配置部分。在安装SQLite.net提供程序之后,该部分由SQLite在machine.config中创建。
appconfig部分的全部目的是帮助您在调用以下命令时获取已配置的.net提供程序列表:
public GetProvidersList() { DataTable table = DbProviderFactories.GetFactoryClasses(); }
答案 6 :(得分:0)
以后的答案
使用上面的配置获取它。我发现这似乎要求提供程序程序集在运行程序可以找到的位置。
/// <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;
}
答案 7 :(得分:0)
在.NET Core 2.1和更高版本中,您可以使用DbProviderFactories.RegisterFactory
以编程方式注册DbProviderFactory
。