我正在使用 Entity Framework Code First 开发一个多租户应用程序。每个租户在数据库中都有不同的模式,但应用程序将为所有租户提供一个上下文和模型。
Entity Framwork 6 能够在同一个数据库中使用具有多个上下文的多个模式,但是我没有找到一种方法可以在一个上下文中使用多个模式。
我已经生成迁移(通过命令行)到默认的“dbo”模式。我想使用这些迁移更新其他模式。
我正在使用 Entity Framework Code First 开发一个多租户应用程序。每个租户在数据库中都有不同的模式,但应用程序将为所有租户提供一个上下文和模型。
Entity Framwork 6 能够在同一个数据库中使用具有多个上下文的多个模式,但是我没有找到一种方法可以在一个上下文中使用多个模式。
我已经生成迁移(通过命令行)到默认的“dbo”模式。我想使用这些迁移更新其他模式。
虽然我同意多上下文绝对是更好的方法(这也是我设置自己的项目的方式),但我想回答您最初的问题,即如何在单个上下文中使用多个模式:
在每个模型的映射配置中,您可以调用“ToTable(myTableName, mySchema)”来修改表所属的架构:
public class MyEntityMap : EntityTypeConfiguration<MyEntity>
{
public MyEntityMap ()
{
HasKey(t => t.MyId);
Property(t => t.MyId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("MyEntity", "MySchema");
}
}
这将允许您在维护单个上下文的同时分别为每个表设置架构。
由于您声明要在不同的模式中使用相同的模型,这使得在不了解更多设置的情况下变得更加困难。如果您只与少数客户打交道并且不介意在代码中维护他们的模式,那么您可以简单地为每个模式创建一个映射(如上所述),然后为每个客户添加一个新的 DbSet。如果您尝试将此扩展到大量客户,那么我强烈建议您研究一种不同的方法,因为当您的 dba 看到不同模式中的 100 多个相同的表而不是在每个表上使用 customerID 列时,他可能会尖叫.
看着这些帖子
http://thedatafarm.com/data-access/digging-in-to-multi-tenant-migrations-with-ef6-alpha/
http://romiller.com/2011/05/23/ef-4-1-multi-tenant-with-code-first/
我想出了这个背景
public class DataLayerBuilder : DbContext
{
private static string conStr = string.Empty ;
private DataLayerBuilder(DbConnection connection, DbCompiledModel model)
: base(connection, model, contextOwnsConnection: false){ }
public DbSet<Person> People { get; set; }
private static ConcurrentDictionary<Tuple<string, string>, DbCompiledModel> modelCache
= new ConcurrentDictionary<Tuple<string, string>, DbCompiledModel>();
/// <summary>
/// Creates a context that will access the specified tenant
/// </summary>
public static DataLayerBuilder Create(string tenantSchema)
{
conStr = ConfigurationManager.ConnectionStrings["ConnSTRName"].ConnectionString;
var connection = new SqlConnection(conStr);
var compiledModel = modelCache.GetOrAdd(
Tuple.Create(conStr, tenantSchema),
t =>
{
var builder = new DbModelBuilder();
builder.HasDefaultSchema(tenantSchema);
builder.Entity<Person>().ToTable("People");
builder.Entity<Contact>().ToTable("Contacts");
var model = builder.Build(connection);
return model.Compile();
});
return new DataLayerBuilder(connection, compiledModel);
}
/// <summary>
/// Creates the database and/or tables for a new tenant
/// </summary>
public static void ProvisionTenant(string tenantSchema)
{
try
{
using (var ctx = Create(tenantSchema))
{
if (!ctx.Database.Exists())
{
ctx.Database.Create();
}
else
{
ctx.Database.Initialize(true);
}
}
}
catch (Exception)
{
throw;
}
}
}
到目前为止,我已经能够使用以下代码添加多个租户
public void ProvisionTest()
{
//Arrange
var tenant = "test2";
//Act
DataLayerBuilder.ProvisionTenant(tenant);
}
}
改进上面的代码我认为你可以编写一个简单的函数来为每个用户更新你的表结构
我希望这有帮助
该解决方案可能最好被视为 Robert Petz 和 alfkonne 答案与一些围绕连接管理和迁移管理的更多工具的组合。对于客户特定的备份目的,我更喜欢每个客户的数据库级别而不是模式。您可以正确执行特定于模式的备份/恢复 IF 设置。但请确保所涉及的任何外部工具都可以处理基于模式的还原。
您可以在单个上下文中使用多个方案。在每个实体或类中,您必须添加以下数据注释:
[Table("TableName", Shema = "ShemaName")]
public class Entity
{
}