在我们公司,我们有一个为1个数据库制作的应用程序。现在我被告知要为每个客户公司使用单独的数据库进行多租户。所以我创建了一个新的数据库,我将存储所有用户并存储他们的公司名称,我将用它来更改数据库。 我想做的事: 1.用户登录 2.后端检查用户的公司名称 3.检索到的公司名称将分配给dbcontext:base,它将使用公司名称切换数据库
当然,我在stackoverflow和其他地方查看了与此相关的其他问题,大多数人都说这是一个解决方案:
public FacilityEntities() : base("name=Demo") { }
public FacilityEntities(string dbConnection) : base(dbConnection)
{
}
并且大多数人都说这很有效。但这对我不起作用。 虽然没有推荐,但我也尝试在运行时更改web.config文件,但每次用户登录时,应用程序都会刷新,无法完成登录过程。
我现在的代码:
登录
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
// This doesn't count login failures towards account lockout
// To enable password failures to trigger account lockout, change to shouldLockout: true
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
returnUrl = CheckFirstLogin(model.Email, returnUrl);
using (var context = new Facility.AdgarWeb.Models.UserCommonDBContext())
{
var companyName = context.CommonUser.Where(x => x.CommonUserEmail == model.Email).FirstOrDefault().CommonUserCompanyName;
new FacilityEntities(companyName.ToString());
}
await OnSignInSuccess(model);
//FormsAuthentication.SetAuthCookie(model.Email, false);
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
}
的DbContext
public partial class FacilityEntities : DbContext
{
public FacilityEntities() : base("name=Demo") { }
public FacilityEntities(string dbConnection) : base(dbConnection)
{
}
}
当我设置调试点时 1。
public FacilityEntities() : base("name=Demo") { }
和 2。
public FacilityEntities(string dbConnection) : base(dbConnection)
我可以看到该应用首先点击第一个代码,然后点击第二个代码,但最终会先回复。
我还发现我有DbFactory文件: DbFactory
FacilityEntities dbContext;
public FacilityEntities Init()
{
return dbContext ?? (dbContext = new FacilityEntities());
}
protected override void DisposeCore()
{
if (dbContext != null)
dbContext.Dispose();
}
}
请有人帮我解决这个问题。
UPDATE 我知道我可以这样使用它:
public FacilityEntities() : base("name=Demo") { }
public FacilityEntities(string dbConnection) : base(dbConnection)
{
}
和
using(var db = new FacilityEntities(dbConnection)
{
//do sth in this db
}
但是如何设置更改的数据库而不必使用using(){}?如何让登录的用户始终使用此数据库?每次我对db执行某些操作时,是否必须调用此新数据库?有没有办法将此更改的数据库设置为此登录用户的“主数据库”?
答案 0 :(得分:2)
对于这个问题,我只需将新实体的第二个连接字符串添加到web.config
<connectionStrings>
<add name="DefaultConnection" .../>
<add name="DefaultConnection2" .../>
</connectionStrings
答案 1 :(得分:1)
您不一定需要从web.config获取连接字符串。您可以使用此代码直接传递连接字符串
public FacilityEntities(string connString)
{
this.Database.Connection.ConnectionString = connString;
}
或者如果您的所有租户的连接字符串相同且只有数据库名称不同,则可以在web.config
中添加连接字符串,并将数据库名称替换为CompanyName
。
<强>的Web.Config 强>
<connectionStrings>
<add name="FacilityEntities" connectionString="Server=.;Database=_DBNAME_;User Id=myUsername; Password=myPassword;" providerName="System.Data.SqlServerCe.4.0"/>
</connectionStrings>
<强>的DbContext 强>
public FacilityEntities(string companyName)
{
string connString = ConfigurationManager.ConnectionStrings["FacilityEntities"].ConnectionString;
connString = connString.Replace("_DBNAME_", companyName);
this.Database.Connection.ConnectionString = connString;
}
这样您就可以动态选择数据库名称。
答案 2 :(得分:0)
您的dbcontext类有2个构造函数。 1个默认值和一个参数化。您需要调用参数化版本
return dbContext ?? (dbContext = new FacilityEntities());
尝试将其更改为
return dbContext ?? (dbContext = new FacilityEntities("New Connection String"));
在任何一种情况下,您都必须修改连接代码。
答案 3 :(得分:0)
根据objectively C创建多个连接字符串的建议,我发现它的工作方式如下:
public FacilityEntities() : base("name=Demo") { } // parameterless
public FacilityEntities(string dbConnection) : base($"name={dbConnection}") { } // with param
唯一缺少的东西是基本构造函数中的 name=...
。
现在您可以通过以下方式(简化代码)使用它:
var dbConnection = "DefaultConnection2";
using (var ctx = new FacilityEntities(dbConnection))
{
// any EF queries using ctx go here
}
注意:由于FacilityEntities可能是由生成的c#代码组成的EDMX的一部分,因此,最好将参数构造函数添加为单独的C#文件(例如FacilityEntities.cs
)。相同的名称空间,其中包含一个partial
类
namespace YourNameSpace // important: use the same namespace your EDMX is using
{
public partial class FacilityEntities
{
public FacilityEntities(string dbConnection) : base($"name={dbConnection}") { }
}
}
无参数构造函数已经存在(在生成的代码中),因此您只能使用参数指定一个。