entity framework在运行时更改连接

我有一个Web API项目引用我的模型和DAL程序集。 用户将看到一个login屏幕,他可以在其中select不同的数据库。

我build立连接string如下:

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

首先,我该如何改变数据上下文的连接?

其次,由于这是一个Web API项目,连接string(在上面设置为login)在整个用户交互中是持久的,还是应该每次都传递给我的数据上下文?

有点迟了这个答案,但我认为有一个可行的方法来做一个整洁的小扩展方法。 我们可以利用EF公约的configuration加上一些小的框架调用。

无论如何,评论的代码和示例用法:

扩展方法类:

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

基本用法:

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

我知道你已经有了基本的function,但认为这会增加一点点的多样性。

DbContext有一个构造函数重载,它接受连接string的名称或连接string本身。 实现自己的版本并将其传递给基础构造函数:

 public class MyDbContext : DbContext { public MyDbContext( string nameOrConnectionString ) : base( nameOrConnectionString ) { } } 

然后,在实例化DbContext时,只需传递一个configuration的连接string或连接string的名称DbContext

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

吉姆·托兰的答案很好,但我得到了错误:关键字不支持“数据源”。 为了解决这个问题,我不得不改变他的这部分代码:

 // add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder (System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString); 

对此:

 // add a reference to System.Configuration var entityCnxStringBuilder = new EntityConnectionStringBuilder { ProviderConnectionString = new SqlConnectionStringBuilder(System.Configuration.ConfigurationManager .ConnectionStrings[configNameEf].ConnectionString).ConnectionString }; 

我真的很抱歉。 我知道我不应该使用答案来回答其他答案,但我的回答是太长的评论:(

创build的类是“部分”的!

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

…你这样称呼它:

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

所以,您只需要为原始自动生成的类(具有相同的类名!)创build一个部分自己的类文件,然后添加一个带有连接string参数的新构造函数,就像之前的Moho答案一样。

之后你可以使用参数化的构造函数对原来的。 🙂

例:

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

在web.config或app.config中添加多个连接string。

然后你可以把它们看成一个string:

 System.Configuration.ConfigurationManager. ConnectionStrings["entityFrameworkConnection"].ConnectionString; 

然后使用string来设置:

 Provider Metadata ProviderConnectionString 

这里最好解释一下:

从web.config读取连接string

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

您可以从web.config中获取连接string,并将其设置在EntityConnectionStringBuilder构造函数中,然后使用EntityConnectionStringBuilder作为上下文的构造函数中的参数。

通过用户名caching连接string。 使用几个通用方法处理从caching添加/检索的简单示例。

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

在我的情况下,我使用ObjectContext而不是DbContext,所以我调整了接受的答案中的代码。

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

我想在应用程序configuration中有多个数据源。 因此,在app.config中设置一段后,我将数据源交换出来,然后作为连接string传递给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; 

这让我有点想弄明白。 我希望它能帮助别人。 我的方式太复杂了。 在这之前。

我有两个扩展方法将正常连接string转换为entity framework格式。 此版本与类库项目很好地协作,无需将连接string从app.config文件复制到主项目。 这是VB.Net,但很容易转换为C#。

 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 

之后,我为DbContext创build了一个部分类:

 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 

创build一个查询:

 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 
 Linq2SQLDataClassesDataContext db = new Linq2SQLDataClassesDataContext(); var query = from p in db.SyncAudits orderby p.SyncTime descending select p; Console.WriteLine(query.ToString()); 

试试这个代码…