现在已经是2019年了,当然有些事情已经改变了,但Franciso的例子确实帮助了我。这是我能找到的最简单的解决方案,也是唯一一个真正起作用的方案。我从他展示的内容中做了一些修改。按照这个完成,你应该会得到一个可行的解决方案。
我必须做一些更改。我将非常明确地说明必须做什么,我将使用我的实际文件名等,以便您不必猜测替换。许多示例也缺乏如何使其最终工作的信息。这个例子包含了你需要知道的所有内容。
这是在Visual Studio 2015 Entityframework 6上构建的,使用MySql Server 8.0.16.0。
不幸的是,MySql连接器和库是一团糟。8.0.xx.0连接器/网和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数据库的模板。
步骤1
我在Web.config中创建了一个特定的连接字符串,它看起来像这样。它允许连接到clientdb_0。
<add name="DefaultClientConnection" providerName="MySql.Data.MySqlClient"
connectionString="server=localhost;user id=xxx;
password=xxxx; persistsecurityinfo=True;database=clientdb_0" />
步骤2
我使用向导创建了一个名为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: strings” 是数据实体所需的,这就是为什么您不能只将标准连接字符串发送到数据实体中。如果您尝试发送初始连接字符串,则会失败。
<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();
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
现在你可以让它运行。为了更好地理解这个例子,知道这个实体的模型是什么样子很好。它非常简单,因为我只是在测试和尝试让它运行。
通过Drilling down
ClientDbUserUpdater.edmx然后进入
ClientDbUserUpdater.tt,您将在modelname.cs中找到您的模型。我的模型称为"user",因此我的文件名称为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”,但这对于演示目的更好。
以下是具有真实名称的实际代码,可在数据库客户端_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小时查看不同的解决方案,但它们都不能正常工作或提供足够的信息来完成它们。正如我所说,找到Franciso的示例让我成功了。
问候,