Entity Framework modifie la connexion à l’exécution

J’ai un projet d’API Web qui référence mon modèle et les assemblages DAL. L’utilisateur est présenté avec un écran de connexion, où il peut sélectionner différentes bases de données.

Je construis la chaîne de connexion comme suit:

public void Connect(Database database) { //Build an SQL connection ssortingng SqlConnectionSsortingngBuilder sqlSsortingng = new SqlConnectionSsortingngBuilder() { DataSource = database.Server, InitialCatalog = database.Catalog, UserID = database.Username, Password = database.Password, }; //Build an entity framework connection ssortingng EntityConnectionSsortingngBuilder entitySsortingng = new EntityConnectionSsortingngBuilder() { Provider = database.Provider, Metadata = Settings.Default.Metadata, ProviderConnectionSsortingng = sqlSsortingng.ToSsortingng() }; } 

Tout d’abord, comment modifier la connexion du contexte de données?

Et deuxièmement, comme il s’agit d’un projet d’API Web, la chaîne de connexion (définie lors de la connexion ci-dessus) est-elle persistante tout au long de l’interaction ou doit-elle être transmise chaque fois à mon contexte de données?

Un peu en retard sur cette réponse, mais je pense qu’il existe un moyen de le faire avec une petite méthode d’extension. Nous pouvons tirer parti de la convention EF plutôt que de la configuration et de quelques appels au cadre.

Quoi qu’il en soit, le code commenté et l’exemple d’utilisation:

classe de méthode d’extension:

 public static class ConnectionTools { // all params are optional public static void ChangeDatabase( this DbContext source, ssortingng initialCatalog = "", ssortingng dataSource = "", ssortingng userId = "", ssortingng password = "", bool integratedSecuity = true, ssortingng configConnectionSsortingngName = "") /* this would be used if the * connectionSsortingng name varied from * the base EF class name */ { try { // use the const name if it's not null, otherwise // using the convention of connection ssortingng = EF contextname // grab the type name and we're done var configNameEf = ssortingng.IsNullOrEmpty(configConnectionSsortingngName) ? source.GetType().Name : configConnectionSsortingngName; // add a reference to System.Configuration var entityCnxSsortingngBuilder = new EntityConnectionSsortingngBuilder (System.Configuration.ConfigurationManager .ConnectionSsortingngs[configNameEf].ConnectionSsortingng); // init the sqlbuilder with the full EF connectionssortingng cargo var sqlCnxSsortingngBuilder = new SqlConnectionSsortingngBuilder (entityCnxSsortingngBuilder.ProviderConnectionSsortingng); // only populate parameters with values if added if (!ssortingng.IsNullOrEmpty(initialCatalog)) sqlCnxSsortingngBuilder.InitialCatalog = initialCatalog; if (!ssortingng.IsNullOrEmpty(dataSource)) sqlCnxSsortingngBuilder.DataSource = dataSource; if (!ssortingng.IsNullOrEmpty(userId)) sqlCnxSsortingngBuilder.UserID = userId; if (!ssortingng.IsNullOrEmpty(password)) sqlCnxSsortingngBuilder.Password = password; // set the integrated security status sqlCnxSsortingngBuilder.IntegratedSecurity = integratedSecuity; // now flip the properties that were changed source.Database.Connection.ConnectionSsortingng = sqlCnxSsortingngBuilder.ConnectionSsortingng; } catch (Exception ex) { // set log item if required } } } 

utilisation de base:

 // assumes a connectionSsortingng name in .config of MyDbEntities var selectedDb = new MyDbEntities(); // so only reference the changed properties // using the object parameters by name selectedDb.ChangeDatabase ( initialCatalog: "name-of-another-initialcatalog", userId: "jackthelady", password: "nomoresecrets", dataSource: @".\sqlexpress" // could be ip address 120.273.435.167 etc ); 

Je sais que vous avez déjà les fonctionnalités de base en place, mais j’ai pensé que cela appendait un peu de diversité.

DbContext a une surcharge de constructeur qui accepte le nom d’une chaîne de connexion ou une chaîne de connexion elle-même. Implémentez votre propre version et transmettez-la au constructeur de base:

 public class MyDbContext : DbContext { public MyDbContext( ssortingng nameOrConnectionSsortingng ) : base( nameOrConnectionSsortingng ) { } } 

Puis passez simplement le nom d’une chaîne de connexion configurée ou une chaîne de connexion elle-même lorsque vous instanciez votre DbContext

 var context = new MyDbContext( "..." ); 

La réponse de Jim Tollan fonctionne très bien, mais j’ai eu l’erreur: “mot de passe non pris en charge” source de données “. Pour résoudre ce problème, j’ai dû modifier cette partie de son code:

 // add a reference to System.Configuration var entityCnxSsortingngBuilder = new EntityConnectionSsortingngBuilder (System.Configuration.ConfigurationManager .ConnectionSsortingngs[configNameEf].ConnectionSsortingng); 

pour ça:

 // add a reference to System.Configuration var entityCnxSsortingngBuilder = new EntityConnectionSsortingngBuilder { ProviderConnectionSsortingng = new SqlConnectionSsortingngBuilder(System.Configuration.ConfigurationManager .ConnectionSsortingngs[configNameEf].ConnectionSsortingng).ConnectionSsortingng }; 

Je suis vraiment désolé. Je sais que je ne devrais pas utiliser les réponses pour répondre à d’autres réponses, mais ma réponse est trop longue pour un commentaire 🙁

La classe créée est «partielle»!

 public partial class Database1Entities1 : DbContext { public Database1Entities1() : base("name=Database1Entities1") { } 

… et vous l’appelez comme ceci:

 using (var ctx = new Database1Entities1()) { #if DEBUG ctx.Database.Log = Console.Write; #endif 

il suffit donc de créer un propre fichier de classe partiel pour la classe d’origine générée automatiquement (avec le même nom de classe!) et d’append un nouveau constructeur avec le paramètre de chaîne de connexion, comme la réponse de Moho auparavant.

Après cela, vous pouvez utiliser un constructeur paramétré contre original. 🙂

Exemple:

 using (var ctx = new Database1Entities1(myOwnConnectionSsortingng)) { #if DEBUG ctx.Database.Log = Console.Write; #endif 

Ajoutez plusieurs chaînes de connexion dans votre fichier web.config ou app.config.

Ensuite, vous pouvez les obtenir sous forme de chaîne comme:

 System.Configuration.ConfigurationManager. ConnectionSsortingngs["entityFrameworkConnection"].ConnectionSsortingng; 

Ensuite, utilisez la chaîne pour définir:

 Provider Metadata ProviderConnectionSsortingng 

Il est mieux expliqué ici:

Lire la chaîne de connexion depuis web.config

 ssortingng _connSsortingng = "metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection ssortingng="data source=localhost;initial catalog=DATABASE;persist security info=True;user id=sa;password=YourPassword;multipleactiveresultsets=True;App=EntityFramework""; EntityConnectionSsortingngBuilder ecsb = new EntityConnectionSsortingngBuilder(_connSsortingng); ctx = new Entities(_connSsortingng); 

Vous pouvez obtenir la chaîne de connexion à partir du fichier web.config, puis la définir dans le constructeur EntityConnectionSsortingngBuilder et utiliser EntityConnectionSsortingngBuilder comme argument dans le constructeur du contexte.

Cache la chaîne de connexion par nom d’utilisateur. Exemple simple utilisant deux méthodes génériques pour gérer l’ajout / récupération du cache.

 private static readonly ObjectCache cache = MemoryCache.Default; // add to cache AddToCache(username, value); // get from cache ssortingng value = GetFromCache(username); if (value != null) { // got item, do something with it. } else { // item does not exist in cache. } public void AddToCache(ssortingng token, T item) { cache.Add(token, item, DateTime.Now.AddMinutes(1)); } public T GetFromCache(ssortingng cacheKey) where T : class { try { return (T)cache[cacheKey]; } catch { return null; } } 

Dans mon cas, j’utilise ObjectContext par opposition à DbContext. J’ai donc modifié le code dans la réponse acceptée à cette fin.

 public static class ConnectionTools { public static void ChangeDatabase( this ObjectContext source, ssortingng initialCatalog = "", ssortingng dataSource = "", ssortingng userId = "", ssortingng password = "", bool integratedSecuity = true, ssortingng configConnectionSsortingngName = "") { try { // use the const name if it's not null, otherwise // using the convention of connection ssortingng = EF contextname // grab the type name and we're done var configNameEf = ssortingng.IsNullOrEmpty(configConnectionSsortingngName) ? Source.GetType().Name : configConnectionSsortingngName; // add a reference to System.Configuration var entityCnxSsortingngBuilder = new EntityConnectionSsortingngBuilder (System.Configuration.ConfigurationManager .ConnectionSsortingngs[configNameEf].ConnectionSsortingng); // init the sqlbuilder with the full EF connectionssortingng cargo var sqlCnxSsortingngBuilder = new SqlConnectionSsortingngBuilder (entityCnxSsortingngBuilder.ProviderConnectionSsortingng); // only populate parameters with values if added if (!ssortingng.IsNullOrEmpty(initialCatalog)) sqlCnxSsortingngBuilder.InitialCatalog = initialCatalog; if (!ssortingng.IsNullOrEmpty(dataSource)) sqlCnxSsortingngBuilder.DataSource = dataSource; if (!ssortingng.IsNullOrEmpty(userId)) sqlCnxSsortingngBuilder.UserID = userId; if (!ssortingng.IsNullOrEmpty(password)) sqlCnxSsortingngBuilder.Password = password; // set the integrated security status sqlCnxSsortingngBuilder.IntegratedSecurity = integratedSecuity; // now flip the properties that were changed source.Connection.ConnectionSsortingng = sqlCnxSsortingngBuilder.ConnectionSsortingng; } catch (Exception ex) { // set log item if required } } } 

Je voulais avoir plusieurs sources de données dans la configuration de l’application. Donc, après avoir configuré une section dans le fichier app.config, j’ai remplacé la source de données, puis transmise-la à dbcontext en tant que chaîne de connexion.

 //Get the key/value connection ssortingng from app config var sect = (NameValueCollection)ConfigurationManager.GetSection("section"); var val = sect["New DataSource"].ToSsortingng(); //Get the original connection ssortingng with the full payload var entityCnxSsortingngBuilder = new EntityConnectionSsortingngBuilder(ConfigurationManager.ConnectionSsortingngs["OriginalSsortingngBuiltByADO.Net"].ConnectionSsortingng); //Swap out the provider specific connection ssortingng entityCnxSsortingngBuilder.ProviderConnectionSsortingng = val; //Return the payload with the change in connection ssortingng. return entityCnxSsortingngBuilder.ConnectionSsortingng; 

Cela m’a pris un peu pour comprendre. J’espère que ça aide quelqu’un. Je rendais les choses trop compliquées. avant ça.

J’ai deux méthodes d’extension pour convertir la chaîne de connexion normale au format Entity Framework. Cette version fonctionne bien avec les projets de bibliothèque de classes sans copier les chaînes de connexion du fichier app.config vers le projet principal. Ceci est VB.Net mais facile à convertir en C #.

 Public Module Extensions  Public Function ToEntityConnectionSsortingng(ByRef sqlClientConnStr As Ssortingng, ByVal modelFileName As Ssortingng, Optional ByVal multipleActiceResultSet As Boolean = True) Dim sqlb As New SqlConnectionSsortingngBuilder(sqlClientConnStr) Return ToEntityConnectionSsortingng(sqlb, modelFileName, multipleActiceResultSet) End Function  Public Function ToEntityConnectionSsortingng(ByRef sqlClientConnStrBldr As SqlConnectionSsortingngBuilder, ByVal modelFileName As Ssortingng, Optional ByVal multipleActiceResultSet As Boolean = True) sqlClientConnStrBldr.MultipleActiveResultSets = multipleActiceResultSet sqlClientConnStrBldr.ApplicationName = "EntityFramework" Dim metaData As Ssortingng = "metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection ssortingng='{1}'" Return Ssortingng.Format(metaData, modelFileName, sqlClientConnStrBldr.ConnectionSsortingng) End Function End Module 

Après cela, je crée une classe partielle pour DbContext:

 Partial Public Class DlmsDataContext Public Shared Property ModelFileName As Ssortingng = "AvrEntities" ' (AvrEntities.edmx) Public Sub New(ByVal avrConnectionSsortingng As Ssortingng) MyBase.New(CStr(avrConnectionSsortingng.ToEntityConnectionSsortingng(ModelFileName, True))) End Sub End Class 

Créer une requête:

 Dim newConnectionSsortingng As Ssortingng = "Data Source=.\SQLEXPRESS;Initial Catalog=DB;Persist Security Info=True;User ID=sa;Password=pass" Using ctx As New DlmsDataContext(newConnectionSsortingng) ' ... ctx.SaveChanges() End Using 
 Linq2SQLDataClassesDataContext db = new Linq2SQLDataClassesDataContext(); var query = from p in db.SyncAudits orderby p.SyncTime descending select p; Console.WriteLine(query.ToSsortingng()); 

essayez ce code …