实体框架-在运行时更改连接字符串(需要解释)
本文关键字:字符串 解释 连接 框架 运行时 实体 | 更新日期: 2023-09-27 18:25:07
我很抱歉将此作为问题发布,但我还无法对我的问题的实际解决方案发表评论,该问题已在此处得到回答。这个解决方案也不能以同样的方式工作。
我使用了这个解决方案,除了实际更改连接之外,扩展似乎自己也能工作。它与web.config
文件中定义的内容相同。如果我删除那个连接字符串,我会得到一个错误,说EF找不到它。
我的方法是数据库优先(此外,它是SQL Server 2000…)和EF版本6
所以我的问题是——它应该如何工作?
- 我必须将与
web.config
中定义的连接名称相同的连接名称传递给扩展方法吗?还是应该不同
我当前的连接字符串如下:
<connectionStrings>
<add name="CATALOGEntities" connectionString="metadata=~/bin/Models'InfoModel.csdl|~/bin/Models'InfoModel.ssdl|~/bin/Models'InfoModel.msl;provider=System.Data.SqlClient;provider connection string="data source=SERVER;initial catalog=CATALOG;integrated security=False;User Id=admin;Password=admin123;MultipleActiveResultSets=True;App=EntityFramework"" providerName="System.Data.EntityClient" />
</connectionStrings>
尝试1:这是我传递给扩展方法的内容:
ConnectionTools.ChangeDatabase(db, "ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false, "ANOTHERCATALOGEntities");
尝试2:也按照VDohnal的建议进行了尝试:
db.ChangeDatabase("ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false, "ANOTHERCATALOGEntities");
尝试3使用:
public partial class CATALOGEntities : DbContext {
public CATALOGEntities(string connectionString) : base(connectionString) { }
public CATALOGEntities() {
// TODO: Complete member initialization
Database.SetInitializer<CATALOGEntities>(null);
}
}
尝试4:也不起作用(假设我在web.config
(源)中定义了2个连接字符串):
if (infoWhole.QueryDetails.IsCountryUK)
{
string strConn = ConfigurationManager.ConnectionStrings["CATALOGEntities"].ConnectionString;
db = new CATALOGEntities(strConn);
}
else
{
string strConn = ConfigurationManager.ConnectionStrings["CATALOGEntitiesUSA"].ConnectionString;
db = new CATALOGEntities(strConn);
}
- 此外,我应该将什么数据源传递给扩展方法——整个
DbContext
或我正在处理的控制器类中定义的数据源,即CATALOGEntities
这是我正在使用的扩展方法:
public static class ConnectionTools
{
// all params are optional
public static void ChangeDatabase(
this CATALOGEntities source,
string initialCatalog = "",
string dataSource = "",
string userId = "",
string password = "",
bool integratedSecuity = false,
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
}
}
}
我的数据库上下文:
public partial class CATALOGEntities : DbContext
{
public CATALOGEntities()
: base("name=CATALOGEntities")
{
}
}
查看您链接到的答案中的代码,它所做的只是从web.config
文件中读取连接字符串,然后使用SqlConnectionStringBuilder
类用新的详细信息替换连接字符串的相关部分。
它不会将修改后的连接字符串写回web.config
。您可以将现有的连接字符串视为一个模板。
我怀疑您可能想要传入与控制器相关的上下文,最后一个参数将是当前连接字符串的名称(除非它与您的上下文同名——在这种情况下,您可以省略它)。
当然,这一切都假设另一个数据库具有相同的模型。
您必须传递一个已在.config中退出的连接名称,或者忽略它。所以这样称呼它:
db.ChangeDatabase( "ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false);
它不会更改应用程序的初始配置连接,只会在运行时更改DbContext(=CATALOGEntities
)的特定现有实例的连接。我认为,这不是你所需要的——每当你创建一个新的DbContext时,你都需要调用它。
我建议你用不同的方法。创建一个工厂,该工厂将基于所选国家/地区生产DbContext的实例。在创建新的DbContext时使用该工厂。另一种方法是更改DbContext(=CATALOGEntities
)类的构造函数。
解决方案:这是我最终成功的方法。
负责访问SQL Server的控制器类:
public class FrequentlyAccessedQueries : Controller
{
private CATALOGEntities db = FrequentlyAccessedQueries.entities();
public static CATALOGEntities entities()
{
QueryDetails qdetails = new QueryDetails();
bool uk = qdetails.IsCountryUK;
if (uk)
{
return new CATALOGEntities("name=CATALOGEntitiesUK");
}
else
{
return new CATALOGEntities("name=CATALOGEntitiesUSA");
}
}
}
DbContext类:
public partial class CATALOGEntities : DbContext
{
public CATALOGEntities(string connectionString)
: base(connectionString)
{
}
}
web.config条目:
<connectionStrings>
<add name="CATALOGEntitiesUK" connectionString="[...]" providerName="System.Data.EntityClient" />
<add name="CATALOGEntitiesUSA" connectionString="[...]" providerName="System.Data.EntityClient" />
</connectionStrings>
这有点像黑客,但可以让你轻松地浏览几个不同的数据库(开发、测试、生产)。它确实要求您在连接到的每个数据库中都有相同的表。如果您需要更改连接字符串中的任何其他内容,希望这将是一个良好的开端。
string DataBaseName = "bab"
string applicationName = Environment.GetCommandLineArgs()[0] ;
string exePath = System.IO.Path.Combine(Environment.CurrentDirectory, applicationName);
var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
var connectionStringsSection = (ConnectionStringsSection)config.GetSection("connectionStrings");
//excuse the poor regex - I'm still figuring it out
connectionStringsSection.ConnectionStrings["Entities"].ConnectionString =
Regex.Replace(connectionStringsSection.ConnectionStrings["Entities"].ConnectionString, "initial catalog.*;(i)", "initial catalog ="+DataBaseName+";i");
config.Save();
ConfigurationManager.RefreshSection("connectionStrings");
Entities test = new Entities();
IEnumerable<int> list = from bobble in test.bobble
where bobble.ID < 250
select bobble.ID;
我完成了所有这些和源代码。Database.Connection.ConnectionString设置正确,但当我实际使用它来读取表时,它失败了,因为它从Web.Config中读取了一个具有屏蔽随机可信度的表。我正在像尝试2一样在运行时更改密码和用户ID。有人能用吗?
mycontext.ChangeDatabase
(
userId: something,
password: something
);
string b= mycontext.Table1
.Where(u => u.name == 'a')
.Select(a => a.ID)
.FirstOrDefault();