Add a DbProviderFactory without an App.Config

前端 未结 8 1749
无人共我
无人共我 2020-12-13 06:52

I am using DbProviderFactories in my data layer (based on Entity Framework) and am using SQLite for my database, but I don\'t have to have a App.Config to have the following

相关标签:
8条回答
  • 2020-12-13 07:09

    In .NET Core 2.1 and later you can use DbProviderFactories.RegisterFactory to programmatically register a DbProviderFactory.

    0 讨论(0)
  • 2020-12-13 07:12

    JoshRivers above posted a solution for SQLite. This can in fact be used for other adapters as well- I was able to get it working for MySQL using his example. I have wrapped this into something a bit more generic. This should be run once the application starts and is for the .NET connector version 6.6.5.0 (but I imagine it is good for other versions as well.)

    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);
    
    0 讨论(0)
  • 2020-12-13 07:12

    Even Later Answer

    Get it using configuration like above. I've found that this seems to require the provider assembly to be somewhere that the running program can find it.

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

    Another method that gets the Instance field directly from the assembly. It works even when the DLL is somewhere else on the system.

        /// <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;
        }
    
    0 讨论(0)
  • 2020-12-13 07:21

    The following will probably cause sunspots and overthrow western civilization. It may even cause a debate about Duct Tape Programming (make it stop!), but it works (for now)

    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) { }
    
    0 讨论(0)
  • 2020-12-13 07:24

    Chosing the DB provider factory programmatically pretty much defeats the purpose. You might as well use the classes specific to SQLite instead of all of those interfaces, no?

    0 讨论(0)
  • 2020-12-13 07:28

    Update for EF 6.0+

    You can add a DbProviderFactory by registering a IDbDependencyResolver and resolving for the type DbProviderFactory. An example of this is below:

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

    you may have to resolve for some additional types as well depending upon what type of overriding you're needing to do and how your project is setup. Basically just start with the code above and continue to debug until you've determined all the services you need to resolve for given your specific requirements.

    You can read more about EF dependency resolution at the links below:

    • 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

    Additionally, you can do this configuration by overriding DbConfiguration as described in the first link above.

    0 讨论(0)
提交回复
热议问题