在运行时更改 DbContext 连接

9
我有三个数据库需要处理: A、B和C,每个数据库都有相同的表(例如:用户、产品)。
我想让用户在运行时决定要使用哪个数据库。 因此我使用了EF5,并创建了3个edbx文件,分别创建了以下类: ADBEntities、BDBEntities和CDBEntities。
如何让用户选择所选的数据库以便获取其用户?
我的意思是,
var dstuff = from user in selecteddb.users
             where user.UserEmail == userEmail
             select user.UserID;

我曾考虑使用反射/基类(DBEntities),但这些想法并没有得到很好的实现。


我为您的场景添加了另一种选择。希望能有所帮助... - jim tollan
4个回答

17

回答有点晚了,但我认为有一个潜在的方法可以使用一个简洁的扩展方法来完成这个任务。就像 slypete(好名字 :-))所说的那样,只需要一个类模型,假设所有表格/属性都是相同的。既然如此,我们可以利用 EF 惯例优于配置以及一些小框架调用。

不管怎样,下面是注释代码和示例用法:

扩展方法类:

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 ADBEntities
var selectedDb = new ADBEntities();
// so only reference the changed properties
// using the object parameters by name
selectedDb.ChangeDatabase
    (
        initialCatalog: "name-of-bdb-initialcatalog",
        userId: "jackthelad",
        password: "nosecrets",
        dataSource: @".\sqlexpress" // could be ip address 100.23.45.67 etc
    );

我目前正是出于你所提到的目的而使用它,到目前为止,它对我非常有帮助。希望它能在你的情况下有所帮助。


7

1
var defaultString = _myContext.Database.GetDbConnection().ConnectionString;
_myContext.Database.GetDbConnection().ConnectionString ="new connection" or _myContext.Database.GetDbConnection().ChangeDatabase()
//your query..
_myContext.Database.GetDbConnection().ConnectionString = defaultString;

0
假设数据库是相同的,你只需要使用生成的类之一。你不需要全部三个(因为它们是相同的)。所以我们挑一个——比如说ADBEntities
现在,你需要允许用户在运行时选择连接(连接字符串)。如果你在app.config/web.config中存储了这三个连接字符串,你可以使用ConfigurationManager在运行时加载它们:
var connections = ConfigurationManager.ConnectionStrings;

展示选项并以某种方式选择其中之一:

foreach (ConnectionStringSettings connection in connections)
    //display connection.Name

ConnectionStringSettings selected_connection = connections[1];

DBContext的其中一个构造函数需要传入一个连接字符串,所以只需将用户选择的连接字符串传递给ADBEntities的构造函数即可:

using (var selecteddb = new ADBEntities(selected_connection.ConnectionString))
{
    var dstuff = from user in selecteddb.users
         where user.UserEmail == userEmail
         select user.UserID;
} 

好的,我已经明白这个想法了(谢谢!),但我有一个问题...ADBEntities没有接收连接字符串的构造函数(尽管它是从具有此构造函数的DBContext派生而来)。 我应该向ADBEntities添加这样一个构造函数吗?还是做些其他的事情...? - user3017270
如果我添加以下构造函数:public AdbEntities(string nameOrConnectionString) : base("name=AdbEntities") { }我会得到这个错误: 指定的模式无效。错误:由于类型“AdbModel.ProductCategory”不可用,关系“AdbModel.AccessCategoriesGroup”未加载。 - user3017270

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接