模式独立的实体框架代码第一次迁移

时间:2015-09-08 11:46:45

标签: c# oracle entity-framework ef-migrations

我使用针对Oracle数据库的Entity Framework迁移很麻烦,因为迁移代码中包含模式名称,而对于Oracle,模式名称也是用户名。我的目标是实现与模式无关的Code First Migrations(能够为测试和生产环境进行一组迁移)。

我已经尝试过这种方法(使用Entity Framework 6.1.3):

1)我在Web.config中有模式名称:

<add key="SchemaName" value="IPR_TEST" />

2)我的DbContext将模式名称作为构造函数参数:

public EdistributionDbContext(string schemaName) 
    : base("EdistributionConnection")
{
    _schemaName = schemaName;
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.HasDefaultSchema(_schemaName);
}

3)我必须为Entity Framework Migrations实现IDbContextFactory才能创建没有无参数构造函数的DbContext:

public class MigrationsContextFactory : IDbContextFactory<EdistributionDbContext>
{
    public EdistributionDbContext Create()
    {
        return new EdistributionDbContext(GetSchemaName());
    }
}

4)我还将迁移历史表配置为正确的模式:

public class EdistributionDbConfiguration : DbConfiguration
{
    public EdistributionDbConfiguration()
    {
        SetDefaultHistoryContext((connection, defaultSchema) 
            => new HistoryContext(connection, GetSchemaName()));
    }
}

5)我修改了为迁移生成的代码,以替换硬编码的模式名称。例如。我将CreateTable("IPR_TEST.Users")替换为CreateTable($"{_schema}.Users")。 (_schema字段根据Web.config中的值设置。

6)我使用MigrateDatabaseToLatestVersion<EdistributionDbContext, MigrationsConfiguration>()数据库初始化程序。

完成所有这些设置后,当我切换到不同的模式时(例如,通过web.config转换),我仍然会遇到问题 - 抛出一个异常,告诉我数据库与我的模型不匹配,并禁用AutomaticMigrations(这是需要的) )。当我尝试执行add-migration时,会生成一个新的迁移,其中所有对象都应该移动到不同的模式(例如:MoveTable(name: "IPR_TEST.DistSetGroups", newSchema: "IPR");,这绝对不是必需的。

对我而言,似乎架构名称在迁移类中的模型字符串哈希中是硬连接的(例如,201509080802305_InitialCreate.resx),即:

<data name="Target" xml:space="preserve">
    <value>H4sIAAAAAAAEAO09227jO... </value>
</data> 

有没有办法告诉Code First Migrations忽略模式名称?

2 个答案:

答案 0 :(得分:1)

您可以创建派生DbContext和&#34;覆盖&#34; modelBuilder.HasDefaultSchema(...)中的OnModelCreating

public class TestDbContext : ProductionDbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.HasDefaultSchema("TestSchema");
    }
}

然后,您可以为两个上下文创建迁移。有关如何在一个项目中创建两个迁移的信息,请参阅this question

这种方法的缺点是你必须保持两个单独的迁移。但它让您有机会调整TestDbContext

的配置

答案 1 :(得分:1)

我遇到了同样的问题,感谢你的帮助,我终于找到了一个似乎运作良好的解决方案:

1)我在Web.config应用程序设置中有架构名称:

<add key="Schema" value="TEST" />

2)我有历史背景:

public class HistoryDbContext : HistoryContext
{
    internal static readonly string SCHEMA;

    static HistoryDbContext()
    {
        SCHEMA = ConfigurationManager.AppSettings["Schema"];
    }

    public HistoryDbContext(DbConnection dbConnection, string defaultSchema)
            : base(dbConnection, defaultSchema)
    { }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.HasDefaultSchema(SCHEMA);
    }
}

3)我有一个引用我的历史数据库上下文的数据库配置:

public class MyDbConfiguration : DbConfiguration
{
    public MyDbConfiguration()
    {
        SetDefaultHistoryContext((connection, defaultSchema) => new HistoryDbContext(connection, defaultSchema));
    }
}

4)这是我的数据库上下文:

public partial class MyDbContext : DbContext
{
    public MyDbContext()
        : base("name=MyOracleDbContext")
    { }

    public static void Initialize()
    {
        DbConfiguration.SetConfiguration(new MyDbConfiguration());
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Migrations.Configuration>());
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.HasDefaultSchema(string.Empty);
    }
}

5)最后,我从global.asax

调用Initialize方法
protected void Application_Start()
{
    MyDbContext.Initialize();
}

关键是将db上下文的默认模式设置为String.Empty,将历史上下文的模式设置为正确的模式。 因此,在创建迁移时,它们与模式无关:迁移的resx的DefaultSchema变量将为空。但是历史数据库上下文模式仍然是正确的,以允许迁移检查通过。

我正在使用以下nugets包:

<package id="EntityFramework" version="6.2.0" targetFramework="net452" />
<package id="Oracle.ManagedDataAccess" version="12.2.1100" targetFramework="net452" />
<package id="Oracle.ManagedDataAccess.EntityFramework" version="12.2.1100" targetFramework="net452" />

然后,您可以在不同的数据库上成功使用Oracle迁移。