添加一个没有App.Config的DbProviderFactory
我在我的数据层(基于entity framework)使用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容器来select数据层,而我的一些数据层不需要App.Config值,或者让它们与数据层紧密相连。
下面可能会引起太阳黑子,推翻西方文明。 它甚至可能引起关于Duct Tape编程的争论(让它停止!),但它工作(现在)
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) { }
上面的JoshRivers发布了SQLite解决scheme。 这实际上也可以用于其他适配器 – 我可以用他的例子为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);
select数据库提供程序工厂程序化几乎失败的目的。 你不如使用特定于SQLite的类而不是所有这些接口,不是吗?
晚答案:
你总是可以直接得到这样一个工厂:
DbProviderFactory factory = System.Data.SQLite.SQLiteFactory.Instance; // (note that the rest of the code is still provider-agnostic.)
或者使用你的IoC容器来parsingDbProviderFactory
,例如:
container.RegisterInstance<DbProviderFactory>(SQLiteFactory.Instance);
我更喜欢不使用DbProviderFactories.GetFactory
因为它需要一个configuration文件的限制(或像JoshRiver的答案中的黑客)。
所有DbProviderFactories.GetFactory
所做的是,它使用提供程序名称查找工厂types的已注册程序集限定名称,然后使用reflection来获取静态Instance
属性的值。
如果你不想使用configuration,根据你的使用情况,上面的方法可能会更方便一些。
更新EF 6.0+
您可以通过注册IDbDependencyResolver
并parsingDbProviderFactory
types来添加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); } }
您可能还需要解决一些其他types的问题,具体取决于您需要执行的重要types以及如何设置项目。 基本上只是从上面的代码开始,并继续debugging,直到您确定了所有需要解决的服务,以满足您的特定需求。
您可以在以下链接阅读更多关于EF依赖关系parsing的信息:
- http://msdn.microsoft.com/en-us/data/jj680697.aspx
- https://entityframework.codeplex.com/wikipage?title=EF%20Configuration%20and%20Extensibility
- https://entityframework.codeplex.com/wikipage?title=Rebuilding%20EF%20providers%20for%20EF6
此外,您可以通过覆盖DbConfiguration
来执行此configuration,如上面第一个链接中所述。
甚至后来的答案
得到它使用像上面的configuration。 我发现这似乎要求运行程序可以find它的地方。
/// <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. } }
另一种直接从程序集中获取实例字段的方法。 即使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; }
看到下面的片段
public DataProviderManager(string ProviderName) { var _Provider = DbProviderFactories.GetFactory(ProviderName); }
你需要传递你的情况是“System.Data.SQLite”的ProviderName。
你不需要创build应用程序configuration部分。 SQLite.net提供程序安装后,该部分由machine.config中的SQLite创build。
appconfig部分的全部目的是在您调用以下命令时帮助您获取configuration的.net提供程序的列表:
public GetProvidersList(){DataTable table = DbProviderFactories.GetFactoryClasses(); }
看到这里的例子: MSDN:获取DbProviderFactory