实体框架 - 在运行时更改连接字符串(需要说明)

时间:2014-10-01 08:10:12

标签: c# entity-framework connection-string

我很抱歉将此问题作为一个问题发布,但我无法根据我的问题的实际解决方案发表评论,这已被回答hereThis solution也无法以同样的方式运作。

我使用了这个解决方案,扩展似乎与实际更改连接不同。它与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=&quot;data source=SERVER;initial catalog=CATALOG;integrated security=False;User Id=admin;Password=admin123;MultipleActiveResultSets=True;App=EntityFramework&quot;" providerName="System.Data.EntityClient" />
</connectionStrings>

ATTEMPT 1:这是我传递给扩展方法的内容:

ConnectionTools.ChangeDatabase(db, "ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false, "ANOTHERCATALOGEntities"); 

ATTEMPT 2:按照VDohnal的建议尝试:

db.ChangeDatabase("ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false, "ANOTHERCATALOGEntities"); 

ATTEMPT 3

public partial class CATALOGEntities : DbContext { 
    public CATALOGEntities(string connectionString) : base(connectionString) { } 
    public CATALOGEntities() { 
        // TODO: Complete member initialization 
        Database.SetInitializer<CATALOGEntities>(null); 
    }
}

ATTEMPT 4:也不起作用(假设我在web.configsource)中定义了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
        }
    }
}

我的DbContext:

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

5 个答案:

答案 0 :(得分:1)

查看链接到的答案中的代码,它所做的只是从web.config文件中读取连接字符串,然后使用SqlConnectionStringBuilder类替换相关部分。具有新细节的连接字符串。

它不会将修改后的连接字符串写回web.config。您可以将现有连接字符串视为模板。

我怀疑你想要传递与控制器相关的上下文,最后一个参数是当前连接字符串的名称(除非它与你的上下文同名 - 其中case,你可以省略它。)

当然,这都假定其他数据库具有相同的模型。

答案 1 :(得分:1)

您必须传递已在.config中延伸的连接名称或省略它。 所以这样称呼:

 db.ChangeDatabase( "ANOTHERCATALOG", "ANOTHERSERVER", "admin", "admin456", false);

它不会更改应用程序的初始配置连接,它只会在运行时更改DbContext(= CATALOGEntities)的特定现有实例的连接。我认为这不是你需要的 - 你需要在创建新的DbContext时调用它。

我建议你使用不同的方法。创建一个工厂,根据所选国家/地区生成DbContext实例。创建新的DbContext时使用该工厂。另一种方法是更改​​DbContext(= CATALOGEntities)类的构造函数。

答案 2 :(得分:0)

解决方案:这最终对我有用。

负责访问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>

答案 3 :(得分:0)

更改数据库连接的另一种方法是动态更改ConfigurationManager ConnectionString 这有点像黑客,但允许您轻松地进入几个不同的数据库(Dev,Test,Prod)。它确实要求您在连接的每个数据库中具有相同的表。 如果您需要更改连接字符串中的任何其他内容,希望这对您来说是一个好的开始。

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;

答案 4 :(得分:0)

我做了所有这些,并且source.Database.Connection.ConnectionString设置正确,但是当我实际使用它读取表时,它失败了,因为它从Web.Config中读取了一个掩盖了随机凭据的表。我正在像Attempt 2这样的运行时期间更改密码和用户ID。有人能正常工作吗?

 mycontext.ChangeDatabase
            (
                userId: something,
                password: something

            );
      string b= mycontext.Table1
                        .Where(u => u.name == 'a')
                        .Select(a => a.ID)
                        .FirstOrDefault();