我使用针对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忽略模式名称?
答案 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迁移。