Ich habe ein Web-API-Projekt, das auf mein Modell und meine DAL-Assemblys verweist. Dem Benutzer wird ein Anmeldebildschirm angezeigt, auf dem er verschiedene Datenbanken auswählen kann.
Ich baue die Verbindungszeichenfolge wie folgt auf:
public void Connect(Database database)
{
//Build an SQL connection string
SqlConnectionStringBuilder sqlString = new SqlConnectionStringBuilder()
{
DataSource = database.Server,
InitialCatalog = database.Catalog,
UserID = database.Username,
Password = database.Password,
};
//Build an entity framework connection string
EntityConnectionStringBuilder entityString = new EntityConnectionStringBuilder()
{
Provider = database.Provider,
Metadata = Settings.Default.Metadata,
ProviderConnectionString = sqlString.ToString()
};
}
Wie ändere ich eigentlich die Verbindung des Datenkontexts?
Und zweitens, da es sich um ein Web-API-Projekt handelt, bleibt die Verbindungszeichenfolge (festgelegt bei Anmeldung gemäß oben) während der gesamten Benutzerinteraktion bestehen oder sollte sie jedes Mal an meinen Datenkontext übergeben werden?
c#
entity-framework
asp.net-web-api
connection-string
Ivan-Mark Debono
quelle
quelle
Antworten:
Ein bisschen spät bei dieser Antwort, aber ich denke, es gibt einen möglichen Weg, dies mit einer netten kleinen Erweiterungsmethode zu tun. Wir können die EF-Konvention gegenüber der Konfiguration sowie einige kleine Framework-Aufrufe nutzen.
Wie auch immer, der kommentierte Code und die Beispielverwendung:
Erweiterungsmethodenklasse:
public static class ConnectionTools { // all params are optional public static void ChangeDatabase( this DbContext source, string initialCatalog = "", string dataSource = "", string userId = "", string password = "", bool integratedSecuity = true, string configConnectionStringName = "") /* this would be used if the * connectionString name varied from * the base EF class name */ { try { // use the const name if it's not null, otherwise // using the convention of connection string = EF contextname // grab the type name and we're done var configNameEf = string.IsNullOrEmpty(configConnectionStringName) ? source.GetType().Name : configConnectionStringName; // add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder (System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString); // init the sqlbuilder with the full EF connectionstring cargo var sqlCnxStringBuilder = new SqlConnectionStringBuilder (entityCnxStringBuilder.ProviderConnectionString); // only populate parameters with values if added if (!string.IsNullOrEmpty(initialCatalog)) sqlCnxStringBuilder.InitialCatalog = initialCatalog; if (!string.IsNullOrEmpty(dataSource)) sqlCnxStringBuilder.DataSource = dataSource; if (!string.IsNullOrEmpty(userId)) sqlCnxStringBuilder.UserID = userId; if (!string.IsNullOrEmpty(password)) sqlCnxStringBuilder.Password = password; // set the integrated security status sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity; // now flip the properties that were changed source.Database.Connection.ConnectionString = sqlCnxStringBuilder.ConnectionString; } catch (Exception ex) { // set log item if required } } }
Grundlegende Verwendung:
// assumes a connectionString 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 );
Ich weiß, dass Sie bereits über die grundlegenden Funktionen verfügen, dachte aber, dies würde ein wenig Abwechslung bringen.
quelle
Controller
die 'Datenbank' des Controllers immer auf die kundenspezifische Datenbank eingestellt wird. Dies befreit mich (oder zukünftige Administratoren / Entwickler) auch davon, für jeden hinzugefügten Client eine neue Verbindungszeichenfolge erstellen zu müssen.// add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder { ProviderConnectionString = new SqlConnectionStringBuilder(System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString).ConnectionString };
DbContext
hat eine Konstruktorüberladung, die den Namen einer Verbindungszeichenfolge oder einer Verbindungszeichenfolge selbst akzeptiert. Implementieren Sie Ihre eigene Version und übergeben Sie sie an den Basiskonstruktor:public class MyDbContext : DbContext { public MyDbContext( string nameOrConnectionString ) : base( nameOrConnectionString ) { } }
Übergeben Sie dann einfach den Namen einer konfigurierten Verbindungszeichenfolge oder einer Verbindungszeichenfolge selbst, wenn Sie Ihre instanziieren
DbContext
var context = new MyDbContext( "..." );
quelle
Die Antwort von Jim Tollan funktioniert hervorragend, aber ich habe den Fehler: Das Schlüsselwort "Datenquelle" wird nicht unterstützt. Um dieses Problem zu lösen, musste ich diesen Teil seines Codes ändern:
// add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder (System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString);
dazu:
// add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder { ProviderConnectionString = new SqlConnectionStringBuilder(System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString).ConnectionString };
Es tut mir wirklich leid. Ich weiß, dass ich keine Antworten verwenden sollte, um auf andere Antworten zu antworten, aber meine Antwort ist zu lang für einen Kommentar :(
quelle
Die erstellte Klasse ist 'partiell'!
public partial class Database1Entities1 : DbContext { public Database1Entities1() : base("name=Database1Entities1") { }
... und du nennst es so:
using (var ctx = new Database1Entities1()) { #if DEBUG ctx.Database.Log = Console.Write; #endif
Sie müssen also nur eine teilweise eigene Klassendatei für die ursprünglich automatisch generierte Klasse (mit demselben Klassennamen!) erstellen und einen neuen Konstruktor mit Verbindungszeichenfolgenparametern hinzufügen, wie zuvor die Antwort von Moho.
Danach können Sie den parametrisierten Konstruktor gegen das Original verwenden. :-)
Beispiel:
using (var ctx = new Database1Entities1(myOwnConnectionString)) { #if DEBUG ctx.Database.Log = Console.Write; #endif
quelle
Fügen Sie Ihrer web.config oder app.config mehrere Verbindungszeichenfolgen hinzu.
Dann können Sie sie als Zeichenfolge erhalten wie:
System.Configuration.ConfigurationManager. ConnectionStrings["entityFrameworkConnection"].ConnectionString;
Verwenden Sie dann die Zeichenfolge, um Folgendes festzulegen:
Es wird hier besser erklärt:
Lesen Sie die Verbindungszeichenfolge aus web.config
quelle
string _connString = "metadata=res://*/Model.csdl|res://*/Model.ssdl|res://*/Model.msl;provider=System.Data.SqlClient;provider connection string="data source=localhost;initial catalog=DATABASE;persist security info=True;user id=sa;password=YourPassword;multipleactiveresultsets=True;App=EntityFramework""; EntityConnectionStringBuilder ecsb = new EntityConnectionStringBuilder(_connString); ctx = new Entities(_connString);
Sie können die Verbindungszeichenfolge aus der Datei web.config abrufen, diese einfach im EntityConnectionStringBuilder-Konstruktor festlegen und den EntityConnectionStringBuilder als Argument im Konstruktor für den Kontext verwenden.
Zwischenspeichern Sie die Verbindungszeichenfolge nach Benutzername. Einfaches Beispiel mit einigen generischen Methoden zum Hinzufügen / Abrufen aus dem Cache.
private static readonly ObjectCache cache = MemoryCache.Default; // add to cache AddToCache<string>(username, value); // get from cache string value = GetFromCache<string>(username); if (value != null) { // got item, do something with it. } else { // item does not exist in cache. } public void AddToCache<T>(string token, T item) { cache.Add(token, item, DateTime.Now.AddMinutes(1)); } public T GetFromCache<T>(string cacheKey) where T : class { try { return (T)cache[cacheKey]; } catch { return null; } }
quelle
In meinem Fall verwende ich den ObjectContext im Gegensatz zum DbContext, daher habe ich den Code in der akzeptierten Antwort zu diesem Zweck optimiert.
public static class ConnectionTools { public static void ChangeDatabase( this ObjectContext source, string initialCatalog = "", string dataSource = "", string userId = "", string password = "", bool integratedSecuity = true, string configConnectionStringName = "") { try { // use the const name if it's not null, otherwise // using the convention of connection string = EF contextname // grab the type name and we're done var configNameEf = string.IsNullOrEmpty(configConnectionStringName) ? Source.GetType().Name : configConnectionStringName; // add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder (System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString); // init the sqlbuilder with the full EF connectionstring cargo var sqlCnxStringBuilder = new SqlConnectionStringBuilder (entityCnxStringBuilder.ProviderConnectionString); // only populate parameters with values if added if (!string.IsNullOrEmpty(initialCatalog)) sqlCnxStringBuilder.InitialCatalog = initialCatalog; if (!string.IsNullOrEmpty(dataSource)) sqlCnxStringBuilder.DataSource = dataSource; if (!string.IsNullOrEmpty(userId)) sqlCnxStringBuilder.UserID = userId; if (!string.IsNullOrEmpty(password)) sqlCnxStringBuilder.Password = password; // set the integrated security status sqlCnxStringBuilder.IntegratedSecurity = integratedSecuity; // now flip the properties that were changed source.Connection.ConnectionString = sqlCnxStringBuilder.ConnectionString; } catch (Exception ex) { // set log item if required } } }
quelle
Ich wollte mehrere Datenquellen in der App-Konfiguration haben. Nachdem ich einen Abschnitt in der app.config eingerichtet hatte, tauschte ich die Datenquelle aus und übergab sie dann als Verbindungszeichenfolge an den dbcontext.
//Get the key/value connection string from app config var sect = (NameValueCollection)ConfigurationManager.GetSection("section"); var val = sect["New DataSource"].ToString(); //Get the original connection string with the full payload var entityCnxStringBuilder = new EntityConnectionStringBuilder(ConfigurationManager.ConnectionStrings["OriginalStringBuiltByADO.Net"].ConnectionString); //Swap out the provider specific connection string entityCnxStringBuilder.ProviderConnectionString = val; //Return the payload with the change in connection string. return entityCnxStringBuilder.ConnectionString;
Ich brauchte ein bisschen, um das herauszufinden. Ich hoffe es hilft jemandem. Ich habe es viel zu kompliziert gemacht. vor dem.
quelle
Ich habe zwei Erweiterungsmethoden, um die normale Verbindungszeichenfolge in das Entity Framework-Format zu konvertieren. Diese Version funktioniert gut mit Klassenbibliotheksprojekten, ohne die Verbindungszeichenfolgen aus der Datei app.config in das primäre Projekt zu kopieren. Dies ist VB.Net, aber einfach in C # zu konvertieren.
Public Module Extensions <Extension> Public Function ToEntityConnectionString(ByRef sqlClientConnStr As String, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True) Dim sqlb As New SqlConnectionStringBuilder(sqlClientConnStr) Return ToEntityConnectionString(sqlb, modelFileName, multipleActiceResultSet) End Function <Extension> Public Function ToEntityConnectionString(ByRef sqlClientConnStrBldr As SqlConnectionStringBuilder, ByVal modelFileName As String, Optional ByVal multipleActiceResultSet As Boolean = True) sqlClientConnStrBldr.MultipleActiveResultSets = multipleActiceResultSet sqlClientConnStrBldr.ApplicationName = "EntityFramework" Dim metaData As String = "metadata=res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl;provider=System.Data.SqlClient;provider connection string='{1}'" Return String.Format(metaData, modelFileName, sqlClientConnStrBldr.ConnectionString) End Function End Module
Danach erstelle ich eine Teilklasse für DbContext:
Partial Public Class DlmsDataContext Public Shared Property ModelFileName As String = "AvrEntities" ' (AvrEntities.edmx) Public Sub New(ByVal avrConnectionString As String) MyBase.New(CStr(avrConnectionString.ToEntityConnectionString(ModelFileName, True))) End Sub End Class
Abfrage erstellen:
Dim newConnectionString As String = "Data Source=.\SQLEXPRESS;Initial Catalog=DB;Persist Security Info=True;User ID=sa;Password=pass" Using ctx As New DlmsDataContext(newConnectionString) ' ... ctx.SaveChanges() End Using
quelle
Verwenden Sie für SQL Server- und SQLite-Datenbanken:
_sqlServerDBsContext = new SqlServerDBsContext(new DbContextOptionsBuilder<SqlServerDBsContext>().UseSqlServer("Connection String to SQL DB").Options);
_sqliteDBsContext = new SqliteDBsContext(new DbContextOptionsBuilder<SqliteDBsContext>().UseSqlite("Connection String to SQLite DB").Options);
quelle
Linq2SQLDataClassesDataContext db = new Linq2SQLDataClassesDataContext(); var query = from p in db.SyncAudits orderby p.SyncTime descending select p; Console.WriteLine(query.ToString());
versuchen Sie diesen Code ...
quelle