web-dev-qa-db-fra.com

Ajouter un DbProviderFactory sans App.Config

J'utilise DbProviderFactories dans ma couche de données (basée sur Entity Framework) et j'utilise SQLite pour ma base de données, mais je n'ai pas besoin d'un App.Config pour avoir le code suivant:

<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>

Au lieu de cela, j'aimerais que ma couche de données mette cela dans un programme. Quelqu'un sait-il comment faire cela?

MODIFIER:  

La raison en est que j'utilise un conteneur IoC pour sélectionner la couche de données et que certaines de mes couches de données n'ont pas besoin des valeurs App.Config ou qu'elles sont liées à la couche de données.

37
JasonRShaver

Ce qui suit va probablement causer des taches solaires et renverser la civilisation occidentale. Cela peut même provoquer un débat sur la programmation de bandes de conduits (arrêtez-le!), Mais cela fonctionne (pour le moment)

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) { }
51
JoshRivers

JoshRivers ci-dessus a posté une solution pour SQLite. Cela peut en fait être utilisé pour d’autres adaptateurs. J’ai réussi à le faire fonctionner pour MySQL en utilisant son exemple. Je l'ai emballé dans quelque chose d'un peu plus générique. Cela devrait être exécuté une fois l'application démarrée et concerne le connecteur .NET version 6.6.5.0 (mais j'imagine que c'est également bon pour les autres versions.)

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);
5
SaxxonPike

Mise à jour pour EF 6.0+

Vous pouvez ajouter une DbProviderFactory en enregistrant une IDbDependencyResolver et en résolvant pour le type DbProviderFactory. Un exemple de ceci est ci-dessous:

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

vous devrez peut-être également résoudre certains types supplémentaires en fonction du type de priorité que vous devez effectuer et de la configuration de votre projet. En gros, commencez simplement par le code ci-dessus et continuez à déboguer jusqu'à ce que vous ayez déterminé tous les services que vous devez résoudre pour vos besoins spécifiques.

Vous pouvez en savoir plus sur la résolution des dépendances EF en cliquant sur les liens ci-dessous:

En outre, vous pouvez effectuer cette configuration en remplaçant DbConfiguration comme décrit dans le premier lien ci-dessus.

3
Ryan Griffith

Le choix par programme de la fabrique de fournisseurs de bases de données annule à peu près l'objectif. Vous pourriez aussi bien utiliser les classes spécifiques à SQLite au lieu de toutes ces interfaces, non?

2
Steven Sudit

REPONSE TARDIVE:

Vous pouvez toujours obtenir directement une usine comme celle-ci:

DbProviderFactory factory = System.Data.SQLite.SQLiteFactory.Instance;
// (note that the rest of the code is still provider-agnostic.)

Ou utilisez votre conteneur IoC pour résoudre la DbProviderFactory, par exemple:

container.RegisterInstance<DbProviderFactory>(SQLiteFactory.Instance);

Je préfère que pas utilise le DbProviderFactories.GetFactory en raison de sa capacité à exiger un fichier de configuration (ou un hack, comme dans @ la réponse de JoshRiver ). 

Tout ce que DbProviderFactories.GetFactory fait, c'est qu'il cherche le nom qualifié d'assemblage du type d'usine à l'aide du nom du fournisseur, puis il obtient la valeur de la propriété static Instance à l'aide de réflexion. 

Si vous ne souhaitez pas utiliser la configuration, l'une des méthodes ci-dessus peut s'avérer plus pratique selon votre cas d'utilisation.

2
Eren Ersönmez

Même plus tard Réponse

Obtenez-le en utilisant la configuration comme ci-dessus. J'ai constaté que cela semble exiger que l'assembleur du fournisseur soit un endroit où le programme en cours peut le trouver.

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

Une autre méthode qui obtient le champ Instance directement à partir de l’Assembly. Cela fonctionne même lorsque la DLL se trouve ailleurs sur le système.

    /// <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
Brian Lakstins

voir l'extrait suivant

    public DataProviderManager(string ProviderName)
    {

       var  _Provider = DbProviderFactories.GetFactory(ProviderName);

    }

vous devez transmettre le nom du fournisseur qui, dans votre cas, est "System.Data.SQLite".

vous n'avez pas besoin de créer la section de configuration de l'application. Cette section est créée par SQLite dans le fichier machine.config après l’installation du fournisseur SQLite.net.

la section appconfig a pour seul objectif de vous aider à obtenir la liste des fournisseurs .net configurés lorsque vous appelez la commande suivante:

public GetProvidersList () { DataTable table = DbProviderFactories.GetFactoryClasses (); }

0