【问题标题】:Add a DbProviderFactory without an App.Config添加没有 App.Config 的 DbProviderFactory
【发布时间】:2010-11-10 04:49:51
【问题描述】:

我在我的数据层(基于实体框架)中使用 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 值,或者将它们硬绑定到数据层。

【问题讨论】:

  • 为什么没有 app.config。如果你不这样做(也许你是一个类库),那么调用应用程序就会这样做。把配置放在那里。
  • 想知道 Jason 是否曾找到答案……我有一个 HTA,它将我们的 .Net 程序集称为 COM 对象。所以,没有app.config。我们正在使用 SQL CE,我们也面临同样的问题。
  • @JohnSaunders:对我来说,我试图让多个 exe 使用相同的配置文件。 EntityFramework 似乎没有兑现 AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"C:\Shared\app.config"); 因此这个问题的用处。

标签: entity-framework sqlite ado.net dbproviderfactories


【解决方案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】:

    迟到的答案:

    你总是可以像这样直接得到一个工厂:

    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 所做的只是,它使用提供者名称查找已注册的工厂类型的程序集限定名称,然后使用反射获取静态Instance 属性的值.

    如果您不想使用配置,根据您的用例,上述方法之一可能更方便。

    【讨论】:

      【解决方案4】:

      EF 6.0+ 更新

      您可以通过注册IDbDependencyResolver 并解析DbProviderFactory 类型来添加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 来完成此配置,如上面第一个链接中所述。

      【讨论】:

        【解决方案5】:

        在 .NET Core 2.1 及更高版本中,您可以使用DbProviderFactories.RegisterFactory 以编程方式注册DbProviderFactory

        【讨论】:

        【解决方案6】:

        以编程方式选择数据库提供程序工厂几乎没有达到目的。您不妨使用特定于 SQLite 的类而不是所有这些接口,不是吗?

        【讨论】:

        • 其实在你的app.config不被读取的时候还是蛮有用的,在你使用F#交互的时候就是这样。
        【解决方案7】:

        看下面的sn-p

            public DataProviderManager(string ProviderName)
            {
        
               var  _Provider = DbProviderFactories.GetFactory(ProviderName);
        
            }
        

        您需要传递在您的情况下为“System.Data.SQLite”的 ProviderName。

        您无需创建应用配置部分。该部分由 SQLite 在安装 SQLite.net 提供程序后在 machine.config 中创建。

        appconfig 部分的全部目的是帮助您在调用以下命令时获取已配置的 .net 提供程序列表:

        公共GetProvidersList() { DataTable 表= DbProviderFactories.GetFactoryClasses(); }

        【讨论】:

          【解决方案8】:

          以后再回答

          使用上述配置获取它。我发现这似乎要求提供程序程序集位于正在运行的程序可以找到它的地方。

              /// <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;
              }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-08-10
            • 2013-09-23
            • 1970-01-01
            • 2010-11-28
            • 1970-01-01
            • 2014-08-21
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多