模式独立的entity framework代码第一次迁移

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

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

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

 

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 { public EdistributionDbContext Create() { return new EdistributionDbContext(GetSchemaName()); } } 

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

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

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

6)我使用MigrateDatabaseToLatestVersion()数据库初始化程序。

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

对我来说,似乎模式名称在迁移类中的模型字符串哈希中的某处是硬连接的(例如,201509080802305_InitialCreate.resx),即:

  H4sIAAAAAAAEAO09227jO...   

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

您可以在DbContext创建派生的DbContext并“覆盖” modelBuilder.HasDefaultSchema(...)

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

然后,您可以为两个上下文创建迁移。 请参阅此问题 ,了解如何在一个项目中创建两个迁移。

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

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

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

  

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)我有一个db配置引用我的历史db上下文:

 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()); } 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包:

    

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