实体框架和在单个上下文中具有多个模式的迁移

时间:2013-03-18 14:44:22

标签: c# entity-framework ef-code-first entity-framework-6

我正在使用Entity Framework Code First开发一个多租户应用程序。每个租户在数据库中都有不同的模式,但应用程序将为所有租户提供单个上下文和模型。

Entity Framwork 6能够在同一个中使用具有多个上下文的多个模式 数据库,但我没有找到一种方法来使用单个Context的多个模式。

我已经(通过命令行)生成了默认“dbo”架构的迁移。我想使用这些迁移更新其他模式。

4 个答案:

答案 0 :(得分:2)

虽然我同意多个上下文绝对是更好的方法(我是如何设置自己的项目),但我想回答一下如何在单个上下文中使用多个模式的原始问题:

在每个模型的映射配置中,您可以调用'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。如果你试图让这个可扩展到大量客户,那么我强烈建议寻找一种不同的方法,因为当他在不同的模式中看到100多个相同的表而不是在每个表上使用customerID列时,你的dba可能会尖叫

答案 1 :(得分:0)

查看这些帖子

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);

    }
}

改进上面的代码我认为你可以编写一个简单的函数来更新每个用户的表结构

我希望这会有所帮助

答案 2 :(得分:0)

最好将解决方案看作是Robert Petz和alfkonne的结合,还有一些关于连接管理和迁移管理的工具。对于客户特定的备份目的,我更喜欢DB级别而非每个客户的架构 您可以正确执行特定于架构的备份/恢复IF设置。但请确保所涉及的任何外部工具都处理基于模式的恢复。

答案 3 :(得分:0)

您可以在单个上下文中使用多个方案。在每个实体或类中,您必须添加以下数据注释:

[Table("TableName", Shema = "ShemaName")]

public class Entity
{

}