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.
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) { }
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);
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:
DbConfiguration
comme décrit dans le premier lien ci-dessus.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?
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.
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;
}
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 (); }