模式独立的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迁移。