42 votes

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'avoir une 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 le fasse de manière programmatique. Quelqu'un connaît-il un moyen de le faire ?

EDIT :

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 de App.Config, ou qu'elles sont liées à la couche de données.

2 votes

Pourquoi n'avez-vous pas d'app.config ? Si vous n'en avez pas (vous êtes peut-être une bibliothèque de classes), alors l'application appelante en a un. Mettez-y la configuration.

0 votes

Je me demande si Jason a déjà trouvé une réponse à cette question... J'ai un HTA qui appelle nos assemblages .Net en tant qu'objets COM. Donc, il n'y a pas de app.config. Nous utilisons SQL CE et nous sommes confrontés au même problème.

0 votes

@JohnSaunders : Pour moi, j'essayais de faire en sorte que plusieurs exe utilisent le même fichier de configuration. EntityFramework ne semblait pas honorer AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", @"C:\Shared\app.config"); D'où l'utilité de cette question.

60voto

JoshRivers Points 2902

Ce qui suit va probablement provoquer des taches solaires et renverser la civilisation occidentale. Il se peut même que cela provoque un débat sur la programmation par ruban adhésif (arrêtez ça !), mais cela fonctionne (pour l'instant).

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 votes

Hehe, ça marche. Pas très joli, mais c'est la seule chose qui existe. Merci !

6voto

SaxxonPike Points 31

JoshRivers a posté ci-dessus une solution pour SQLite. Elle peut en fait être utilisée pour d'autres adaptateurs. J'ai réussi à la faire fonctionner pour MySQL en utilisant son exemple. J'ai intégré cette solution dans quelque chose d'un peu plus générique. Elle doit être exécutée au démarrage de l'application et est destinée au connecteur .NET version 6.6.5.0 (mais j'imagine qu'elle est valable pour d'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);

5voto

Eren Ersönmez Points 13491

RÉPONSE 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 bien utilisez votre conteneur IoC pour résoudre la DbProviderFactory par exemple :

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

Je préfère no pour utiliser le DbProviderFactories.GetFactory à cause de sa limitation qui nécessite un fichier de configuration (ou un hack comme dans La réponse de @JoshRiver ).

Tous DbProviderFactories.GetFactory c'est qu'il recherche les données enregistrées nom qualifié pour l'assemblage du type factory en utilisant le nom du fournisseur, puis il récupère la valeur de l'objet statique Instance en utilisant la réflexion.

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

3voto

Ryan Griffith Points 471

Mise à jour pour les versions EF 6.0 et plus

Vous pouvez ajouter un DbProviderFactory en enregistrant un IDbDependencyResolver et la résolution pour le type DbProviderFactory . En voici un exemple :

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

il se peut que vous deviez résoudre certains types supplémentaires, en fonction du type de remplacement dont vous avez besoin et de la façon dont votre projet est configuré. Commencez par le code ci-dessus et continuez à déboguer jusqu'à ce que vous ayez déterminé tous les services que vous devez résoudre en fonction de vos besoins spécifiques.

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

De plus, vous pouvez effectuer cette configuration en surchargeant le fichier DbConfiguration comme décrit dans le premier lien ci-dessus.

2voto

Steven Sudit Points 13793

Le choix programmatique de la fabrique du fournisseur de BD va à l'encontre du but recherché. Vous pourriez tout aussi bien utiliser les classes spécifiques à SQLite au lieu de toutes ces interfaces, non ?

5 votes

En fait, c'est très utile lorsque votre app.config n'est pas lu, ce qui est le cas lorsque vous utilisez F# interactive.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X