将多个数据库与单个DbContext和Entites一起使用,并在运行时生成Conn String

Awa*_*ood 3 c# sql-server asp.net-mvc entity-framework

我正在开发一个MVC 5应用程序.最初我使用EF6 DataBase第一种方法使用单个数据库,我使用我的DbContext实例访问我的数据库,该数据库有102个表.我将其实例声明为:

private MyEntities db = new MyEntities();

现在我想允许多家公司使用我的应用程序,为此我必须为每个新公司创建一个新的数据库.我通过向DbContext声明另一个构造函数来实现此目的,如下所示:

public partial class NewEntities : DbContext
{
    public NewEntities(string name)
        : base(name)
    {
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其实例声明为:

public NewEntities de = new NewEntities((ConfigurationManager.ConnectionStrings["NewEntities123"]).ToString());
Run Code Online (Sandbox Code Playgroud)

然后我打电话

db.Database.Create();

我的新数据库已成功创建.但是在这个方案中,每次我想添加数据库时,我都必须在我的Web.config文件中声明一个新的连接字符串.

是否有任何方法,根据配置文件中的公司名称自动生成连接字符串,然后传递给构造函数以创建具有该名称的新数据库?

此外,我想为每个公司使用相同的"db"实例和DbContext访问我的所有控制器方法,以便我的相同代码可以用于所有公司.如何为多个数据库访问单个DbContext及其实例?

我已经看过这个问题,因为它说没有方法.但那么我的应用程序如何适用于多个用户?

Rez*_*aei 6

在数据库优先工作时,拥有带映射的edmx文件,您可以通过这种方式创建和使用数据库.

为您的上下文构造函数添加一个重载(就像您一样),例如:

public TenantDBContainer(string connectionString)
    : base(connectionString)
{
}
Run Code Online (Sandbox Code Playgroud)

然后当你需要创建数据库时,如果不存在,使用 yourContextInstance.Database.CreateIfNotExists();

var connectionStringTemplate =
    @"metadata=res://*/Models.TenantDB.csdl|res://*/Models.TenantDB.ssdl|res://*/Models.TenantDB.msl;" +
    @"provider=System.Data.SqlClient;" +
    @"provider connection string=""data source=(localdb)\v11.0;" +
    @"initial catalog={0};"+
    @"user id={1};password={2};" +
    @"MultipleActiveResultSets=True;App=EntityFramework"";";

var TenandDBName = "Database Name Based on Tenant";
var TenantUserName = "UserName Based on Tenant";
var TenantPassword = "Password Based on Tenant";
var connectionString = string.Format(connectionStringTemplate, TenandDBName, TenantUserName, TenantPassword);
var db = new TenantDBEntities(connectionString);
db.Database.CreateIfNotExists();
Run Code Online (Sandbox Code Playgroud)

注意:

  • 这样,在多租户应用程序中,您可以为每个租户创建数据库并使用它.
  • 您无需更改webconfig以在其中添加连接字符串,您只需在运行时创建连接字符串即可.
  • 现在,您可以根据租户检测策略设计结构以获取上下文.

作为简化案例的示例,假设您有一个静态方法,可以为您返回上下文实例,例如:

Public class DbHelper
{
    public static TenantDBEntities GetDbContext(string tenantName)
    {
        var connectionStringTemplate =
            @"metadata=res://*/Models.TenantDB.csdl|res://*/Models.TenantDB.ssdl|res://*/Models.TenantDB.msl;" +
            @"provider=System.Data.SqlClient;" +
            @"provider connection string=""data source=(localdb)\v11.0;" +
            @"initial catalog={0};"+
            @"integrated security=True;" +
            @"MultipleActiveResultSets=True;App=EntityFramework"";";

        var TenandDBName = "TenantDB_" + tenantName;
        var connectionString = string.Format(connectionStringTemplate, TenandDBName);
        var db = new TenantDBEntities(connectionString);
        db.Database.CreateIfNotExists();

        return db;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且假设我的租户dettection策略仅仅基于请求URL或其他东西.

现在,例如在Index操作中的ProductController中,您可以这样使用它;

public ActionResult Index()
{
    var tenantName = "Get tenant based on your strategy, for example tenant1 or tenant2";
    var db= DbHelper.GetDbContext(tenantName)
    var model= db.Products.ToList();
    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

当每个租户使用此操作时,它将连接到适合该租户的数据库,如果数据库不存在,则首先创建它然后使用它.

这样每个租户都会看到自己的产品.