[英]Entity Framework and Migration with multiple schemas in a single Context
I am developing a multi-tenant application with Entity Framework Code First. 我正在使用Entity Framework Code First开发一个多租户应用程序。 Each tenant will have a different schema in the database, but the application will have a single Context and model for all tenants.
每个租户在数据库中都有不同的模式,但应用程序将为所有租户提供单个上下文和模型。
The Entity Framwork 6 is able to use multiple schemas with multiple contexts in the same database, but I didn't find a way to use multiple schemas with a single Context. Entity Framwork 6能够在同一个数据库中使用多个具有多个上下文的模式,但是我没有找到一种方法来使用单个上下文的多个模式。
I have generated migrations (by command line) to the default “dbo” schema. 我已经(通过命令行)生成了对默认“dbo”架构的迁移。 I would like to update other schemas using these migrations.
我想使用这些迁移更新其他模式。
While I agree that multiple context is absolutely the better way to go (and is how I have my own projects setup), I wanted to answer your original question of how to use multiple schemas in a single context: 虽然我同意多个上下文绝对是更好的方法(并且我是如何设置自己的项目),但我想回答一下如何在单个上下文中使用多个模式的原始问题:
Inside of your mapping configuration for each model you can call 'ToTable(myTableName, mySchema)' to modify the schema to which a table belongs: 在每个模型的映射配置中,您可以调用'ToTable(myTableName,mySchema)'来修改表所属的模式:
public class MyEntityMap : EntityTypeConfiguration<MyEntity>
{
public MyEntityMap ()
{
HasKey(t => t.MyId);
Property(t => t.MyId)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
ToTable("MyEntity", "MySchema");
}
}
This will allow you to set the schema for each table separately while maintaining a single context. 这将允许您分别为每个表设置架构,同时保持单个上下文。
Since you stated that you want to use the same model in different schemas that makes it a little more difficult without knowing more about your setup. 既然您声明要在不同的模式中使用相同的模型,那么在不了解您的设置的情况下会更加困难。 If you are dealing only with a handful of customers and don't mind maintaining their schemas in code then you can simply create a map for each schema (as above) and then add a new DbSet for each customer.
如果您只与少数客户打交道并且不介意在代码中维护他们的模式,那么您可以简单地为每个模式创建一个映射(如上所述),然后为每个客户添加一个新的DbSet。 If you are trying to make this scalable up to a large number of customers then I would highly suggest looking into a different approach because your dba might scream when he sees 100+ identical tables in different schemas as opposed to using a customerID column on each table.
如果你试图让这个可扩展到大量客户,那么我强烈建议寻找一种不同的方法,因为当他在不同的模式中看到100多个相同的表而不是在每个表上使用customerID列时,你的dba可能会尖叫。
Looking at these posts 看看这些帖子
http://thedatafarm.com/data-access/digging-in-to-multi-tenant-migrations-with-ef6-alpha/ 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/ http://romiller.com/2011/05/23/ef-4-1-multi-tenant-with-code-first/
I came up with this context 我想出了这个背景
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;
}
}
}
So far I've been able to add Multiple Tenants Using the following Code 到目前为止,我已经能够使用以下代码添加多个租户
public void ProvisionTest()
{
//Arrange
var tenant = "test2";
//Act
DataLayerBuilder.ProvisionTenant(tenant);
}
}
Improving upon the above code I think you can write a simple Function to update your table structures for each user 改进上面的代码我认为你可以编写一个简单的函数来更新每个用户的表结构
I hope this helps 我希望这有帮助
The solution is probably best seen as a combination of both Robert Petz and alfkonne answers with a few more tools around connection management and migration management. 该解决方案可能最好看作是Robert Petz和alfkonne的结合,还有一些关于连接管理和迁移管理的工具。 I prefer DB level not schema per Customer for customer specific backup purposes.
对于客户特定的备份目的,我更喜欢DB级别而非每个客户的架构 You can do schema specific backup/restore IF setup properly.
您可以正确执行特定于架构的备份/恢复IF设置。 But make sure any external tools involved deal with schema based restore.
但请确保所涉及的任何外部工具都处理基于模式的恢复。
You can use multiple schemes in a single context. 您可以在单个上下文中使用多个方案。 In each of the entities or class you must add the following Data Annotations:
在每个实体或类中,您必须添加以下数据注释:
[Table("TableName", Shema = "ShemaName")]
public class Entity
{
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.