Ich habe ein Web-API-Projekt, das auf meine Modell- und DAL-Baugruppen verweist. Dem Benutzer wird ein Anmeldebildschirm angezeigt, auf dem er verschiedene Datenbanken auswählen kann.
Ich baue die Verbindungszeichenfolge wie folgt:
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()
};
}
Erstens, wie kann ich die Verbindung des Datenkontexts tatsächlich ändern?
Und zweitens, da es sich um ein Web-API-Projekt handelt, ist die Verbindungszeichenfolge (bei Login oben festgelegt) während der gesamten Benutzerinteraktion dauerhaft oder sollte sie jedes Mal in meinen Datenkontext übergeben werden?
Zu dieser Antwort etwas spät, aber ich denke, es gibt einen möglichen Weg, dies mit einer ordentlichen kleinen Erweiterungsmethode zu tun. Wir können die EF-Konvention gegenüber der Konfiguration und ein paar kleine Rahmenaufrufe nutzen.
Wie auch immer, der kommentierte Code und die Verwendung von Beispielen:
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
}
}
}
grundnutzung:
// 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 Grundfunktionalität verfügen, aber dies würde ein wenig Abwechslung bewirken.
DbContext
verfügt über eine Konstruktorüberladung, die den Namen einer Verbindungszeichenfolge oder einer Verbindungszeichenfolge selbst akzeptiert. Implementieren Sie Ihre eigene Version und übergeben Sie diese an den Basiskonstruktor:
public class MyDbContext : DbContext
{
public MyDbContext( string nameOrConnectionString )
: base( nameOrConnectionString )
{
}
}
Übergeben Sie einfach den Namen einer konfigurierten Verbindungszeichenfolge oder eine Verbindungszeichenfolge selbst, wenn Sie Ihre DbContext
-Instanz instanziieren.
var context = new MyDbContext( "..." );
Die Antwort von Jim Tollan funktioniert großartig, aber ich habe das Error: Schlüsselwort "Datenquelle" 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);
zu diesem:
// 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 :(
Die erstellte Klasse ist "partiell"!
public partial class Database1Entities1 : DbContext
{
public Database1Entities1()
: base("name=Database1Entities1")
{
}
... und Sie nennen es so:
using (var ctx = new Database1Entities1())
{
#if DEBUG
ctx.Database.Log = Console.Write;
#endif
sie müssen also nur eine partielle own class-Datei für die ursprünglich automatisch generierte Klasse erstellen (mit demselben Klassennamen!) und einen neuen Konstruktor mit Verbindungszeichenfolge-Parameter hinzufügen, wie zuvor Mohos Antwort.
Danach können Sie den parametrisierten Konstruktor für das Original verwenden. :-)
beispiel:
using (var ctx = new Database1Entities1(myOwnConnectionString))
{
#if DEBUG
ctx.Database.Log = Console.Write;
#endif
Fügen Sie mehrere Verbindungszeichenfolgen in Ihrer web.config oder app.config hinzu.
Dann können Sie sie als Zeichenfolge erhalten:
System.Configuration.ConfigurationManager.
ConnectionStrings["entityFrameworkConnection"].ConnectionString;
Verwenden Sie dann die Zeichenfolge, um Folgendes festzulegen:
Provider
Metadata
ProviderConnectionString
Es ist besser hier erklärt:
In meinem Fall verwende ich ObjectContext im Gegensatz zu DbContext, daher habe ich den Code in der akzeptierten Antwort für diesen Zweck angepasst.
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
}
}
}
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 als Verbindungsstring an 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;
Das hat mich ein bisschen geklärt. Ich hoffe es hilft jemandem. Ich habe es viel zu kompliziert gemacht. vor dem.
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. Legen Sie diese im EntityConnectionStringBuilder-Konstruktor fest und verwenden Sie den EntityConnectionStringBuilder als Argument im Konstruktor für den Kontext.
Zwischenspeichern Sie die Verbindungszeichenfolge nach Benutzername. Ein einfaches Beispiel, bei dem einige generische Methoden zum Hinzufügen/Abrufen aus dem Cache verwendet werden.
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;
}
}
Ich habe zwei Erweiterungsmethoden zum Konvertieren der normalen Verbindungszeichenfolge in das Entity Framework-Format. Diese Version funktioniert gut mit Klassenbibliothekprojekten, ohne die Verbindungszeichenfolgen aus der Datei app.config in das Primärprojekt zu kopieren. Dies ist VB.Net, aber leicht 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