Независимый от схемы модуль Entity Framework First Migrations
У меня возникают проблемы с использованием миграции Entity Framework, ориентированной на базы данных Oracle, поскольку имя схемы включено в код миграции, а для Oracle имя схемы также является именем пользователя. Моя цель - иметь независимые от схемы кодовые первые миграции (чтобы иметь возможность иметь один набор миграций для тестирования и производства).
Я уже пробовал этот подход (используя Entity Framework 6.1.3):
1) У меня есть имя схемы в Web.config:
<add key="SchemaName" value="IPR_TEST" />
2) My DbContext принимает имя схемы как параметр конструктора:
public EdistributionDbContext(string schemaName)
: base("EdistributionConnection")
{
_schemaName = schemaName;
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema(_schemaName);
}
3) Мне пришлось реализовать IDbContextFactory для Entity Framework Migrations, чтобы иметь возможность создавать мой 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");
, что определенно не нужно.
Мне кажется, что имя схемы жестко связано где-то в модели string-hash в классе миграции (например, 201509080802305_InitialCreate.resx), то есть:
<data name="Target" xml:space="preserve">
<value>H4sIAAAAAAAEAO09227jO... </value>
</data>
Это там способ, как сообщить Code First Migrations игнорировать имя схемы?
Ответы
Ответ 1
Вы можете создать производные DbContext
и "override" modelBuilder.HasDefaultSchema(...)
в OnModelCreating
:
public class TestDbContext : ProductionDbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.HasDefaultSchema("TestSchema");
}
}
Затем вы можете создавать миграции для обоих контекстов. См. этот вопрос о том, как создать две миграции в одном проекте.
Недостатком этого подхода является то, что вы должны поддерживать две отдельные миграции. Но это дает вам возможность настроить конфигурацию вашего TestDbContext
.
Ответ 2
Я столкнулся с той же проблемой, и благодаря вашему aproach я наконец нашел решение, которое, кажется, работает очень хорошо:
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) У меня есть конфигурация db, которая ссылается на мой контекст db истории:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetDefaultHistoryContext((connection, defaultSchema) => new HistoryDbContext(connection, defaultSchema));
}
}
4) И это мой контекст db:
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) Наконец, я вызываю метод Initialize из global.asax
protected void Application_Start()
{
MyDbContext.Initialize();
}
Ключ должен установить стандартную схему контекста db в String.Empty и схему контекста истории к правильной.
Поэтому, когда вы создаете свои миграции, они независимы от схемы: переменная DefaultSchema resx миграции будет пустой. Но схема контекста db истории по-прежнему правильна, чтобы пропускать проверки миграции.
Я использую следующие пакеты 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 в разных базах данных.