现在是 2019 年,当然事情发生了一些变化,但弗朗西索的例子确实帮助了我。这是我能找到的最简单的解决方案,也是唯一真正有效的解决方案。我确实从他所展示的内容中进行了一些更改。按照这个完成,你应该最终得到一个可行的解决方案。
我不得不改变一些事情。我将非常明确地说明必须做什么,并且我将使用我的实际文件名等,这样您就不必猜测替换。许多示例也缺少关于如何使其最终起作用的示例。这个例子有你需要知道的一切。
这是基于 Visual Studio 2015 Entityframework 6 使用 MySql 服务器 8.0.16.0 构建的。
不幸的是,MySql 连接器和库是一团糟。 8.0.xx.0 的连接器/net 和 MySql.Data.Entity.EF6 和 MySql.Data 完全没用。
我已经安装了 Connector Net 6.10.7.0、MySql.Data.Entity.EF6 6.10.7.0 和 MySql.Data 6.10.7.0。这对我有用,我会强烈反对改变这一点。
这是用于 MySql 但我真的不知道为什么它不能用于任何数据库。
场景
我有一个多租户情况,我有一个公共数据库和多个租户数据库,每个客户一个客户 ID 保存在公共数据库中用于登录和授权,客户 ID 指示使用哪个数据库。客户端数据库都称为 myclientdb_x,其中 x 是客户端编号。 myclientdb_1、myclientdb_2、myclientdb_35 等等。
我需要动态切换到代码当前服务的任何 clientdb_x。有一个名为 myclient_0 的初始数据库客户端,它是所有其他 myclient_x 数据库的模板。
第一步
我为此在我的 Web.config 中创建了一个特定的连接字符串,它看起来像这样。它允许连接到 clientdb_0
<add name="DefaultClientConnection" providerName="MySql.Data.MySqlClient"
connectionString="server=localhost;user id=xxx;
password=xxxx; persistsecurityinfo=True;database=clientdb_0" />
第二步
我使用向导创建了一个名为 ClientDbUserUpdater 的新实体。数据实体被调用
ClientDbUserUpdater.edmx
我告诉它使用“DefaultClientConnection”作为数据库连接
我告诉它在 Web.config 中保存这个新的连接字符串
这在 Web.config 文件中创建了新的实体连接字符串,它看起来像
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database=myclient_0"" providerName="System.Data.EntityClient" />
您可能需要挖掘一下,因为向导不擅长将 \n 放在适当的位置。
请注意,这个连接字符串与初始连接字符串基本相同,只是它的名称和它具有
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
数据实体需要 res: 字符串,这也是为什么您不能只将标准连接字符串发送到数据实体的原因。
如果你尝试在初始连接字符串中发送
<add name="DefaultClientConnection" providerName="MySql.Data.MySqlClient"
connectionString="server=localhost;user id=xxx;
password=xxxx; persistsecurityinfo=True;database=clientdb_0" />
你会得到一个例外
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
第三步
这个新的连接字符串是您需要更改的。我尚未对其进行测试,但我很确定如果使用向导更改数据实体模型,您将需要再次进行此更改。
取字符串:
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database=myclient_0"" providerName="System.Data.EntityClient" />
并将其更改为:
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database={0}"" providerName="System.Data.EntityClient" />
请注意,唯一更改的部分是 database=myclient_0 到 database={0}
第 4 步
数据实体在 ClientDbUserUpdater.edmx 后面创建了一些代码。该文件名为 ClientDbUserUpdater.Context.cs。
代码是...
namespace what.ever.your.namespace.is
{
using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
public partial class client_0Entities : DbContext
{
public client_0Entities()
: base("name=client_0Entities")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<user> users { get; set; }
}
}
请注意,这是一个部分类。这意味着你可以扩展这个类并添加一个新的构造函数。
添加以下类。
using System;
using System.Configuration ;
using System.Data.Entity ;
namespace what.ever.your.namespace.is
{
public partial class client_0Entities : DbContext
{
public client_0Entities(string dbName) : base(GetConnectionString(dbName))
{
}
public static string GetConnectionString(string dbName)
{
var connString = ConfigurationManager.ConnectionStrings["client_0Entities"].ConnectionString.ToString();
// obviously the next 2 lines could be done as one but creating and
// filling a string is better for debugging. You can see what happened
// by looking a conn
// return String.Format(connString, dbName);
string conn = String.Format(connString, dbName);
return conn ;
}
}
}
该类添加了一个新的构造函数,它允许您获取数据实体模型的基本连接字符串,如上所示:
<add name="myclient_0Entities" connectionString="metadata=
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.csdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.ssdl|
res://*/Areas.Authorizations.Models.ClientDbUserUpdater.msl;
provider=MySql.Data.MySqlClient;provider connection string="
server=localhost;user id=xxxx;password=yyyyy;
persistsecurityinfo=True;database={0}"" providerName="System.Data.EntityClient" />
并在运行时对其进行修改以更改架构。
新分部类中的 String.Format() 调用在运行时换出此连接字符串中的数据库模式名称。
至此所有配置都完成了。
第 5 步
现在你可以开始了。为了更好地理解这个例子,很高兴知道这个实体的模型是什么样的。这很简单,因为我只是在测试并尝试实现它。
向下钻取 ClientDbUserUpdater.edmx 并进入 ClientDbUserUpdater.tt,您将在 modelname.cs 中找到您的模型。我的模型被称为“用户”,所以我的文件名为 user.cs
namespace what.ever.your.namespace.is
{
using System;
using System.Collections.Generic;
public partial class user
{
public int UserId { get; set; }
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<bool> Active { get; set; }
}
}
现在您通常可以像这样访问您的模型。
client_0Entities _client_0Entities = new client_0Entities("schemaName");
并且此代码可以在您的解决方案中可以看到类 client_0Entities 的任何位置。
这实际上是类似于以下 3 个中的任何一个的行,它们分别连接到数据库 client_19、client_47 和 client_68。
client_0Entities _client_0Entities = new client_0Entities("client_19");
client_0Entities _client_0Entities = new client_0Entities("client_47");
client_0Entities _client_0Entities = new client_0Entities("client_68");
以下是在我的系统上运行的实际代码示例。显然我不会在“client_19”中硬编码,但它更适合演示目的。
这是具有真实姓名的实际代码,它可以在数据库 client_19 上的用户表中添加一个新行
string _newSchema = "client_19"
using(client_0Entities _client_0Entities = new client_0Entities(_newSchema))
{
user _user = new user();
_user.UserId = 201;
_user.Email = "someone@someplace.com"
_user.FirstName ' "Someone";
_user.LastName = "New";
_user.Active = true;
client_0Entities.users.Add ( _user ) ;
client_0Entities.SaveChangesAsync ( ) ;
}
希望这对某些人有所帮助。我花了大约 20 小时研究不同的解决方案,这些解决方案根本不起作用或提供足够的信息来完成它们。正如我所说,找到弗朗西索的例子让我能够让它发挥作用。
问候,