Путаница с EF Auto Migrations и раздачей - раздача при каждом запуске программы

Я недавно изменил приложение, чтобы использовать для разработчика следующее:

DropCreateDatabaseIfModelChanges<Context>


Для использования:

public class MyDbMigrationsConfiguration: DbMigrationsConfiguration<GrsEntities>
{
    public MyDbMigrationsConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
    }
}


В моем контексте БД у меня есть:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Tell Code First to ignore PluralizingTableName convention
    // If you keep this convention then the generated tables will have pluralized names.
    modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

    //set the initializer to migration
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<GrsEntities, MigrationConfig>());
}

Я переопределил Seed (context) в DbMigrationsConfiguration, используя расширение AddOrUpdate, где я просто использовал Add раньше с заполнением в drop db (DropCreateDatabaseIfModelChanges).

Меня беспокоит то, что миграция выполняется при каждом запуске приложения независимо от того, есть ли какие-либо изменения в DbContext. Каждый раз, когда я запускаю приложение (библиотека запускается через службу), инициализатор запускается, как и Seed. Мое ожидаемое поведение - проверка необходимости миграции (за кулисами проверка, соответствует ли модель физической БД), затем обновление любых новых / удаленных таблиц / столбцов и запуск семени только в том случае, если что-то изменилось.

В моем тестировании семя запускается каждый раз, что работает, но, по-видимому, неэффективно и не соответствует моим ожиданиям. К сожалению, документация MSDN весьма ограничена.

Я полностью неправильно использую MigrateDatabaseToLatestVersion? Есть ли способ получить ожидаемое поведение (т.е. только начальное значение, если есть изменение модели), или я должен просто изменить свой метод начального значения, чтобы ожидать его запуска при каждом запуске приложения?




Ответы (3)


Тот факт, что метод Seed запускался только при изменении базы данных, сильно ограничивал инициализаторы базы данных, поставляемые в EF 4.1. Это было ограничением, потому что иногда вам нужно было обновить исходные данные без изменения базы данных, но для этого вам приходилось искусственно создавать впечатление, что база данных изменилась.

С Migrations использование Seed стало немного другим, потому что больше нельзя было предполагать, что база данных была запущена пустой - в конце концов, это своего рода точка Migrations. Таким образом, метод Seed в Migrations должен предполагать, что база данных существует и, возможно, уже содержит данные в ней, но эти данные, возможно, потребуется обновить, чтобы учесть изменения, внесенные в базу данных для Migrations. Отсюда и использование AddOrUpdate.

Итак, теперь у нас есть ситуация, когда Seed должен быть написан с учетом существующих данных, что означает, что на самом деле нет необходимости увековечивать ограничения метода EF 4.1 Seed, так что вам нужно будет создать впечатление, что база данных изменилась. просто для того, чтобы запустить Seed. Следовательно, Seed теперь запускается каждый раз, когда контекст впервые используется в домене приложения. Это не должно изменить способ реализации Seed, поскольку он должен обрабатывать случай, когда данные уже присутствуют.

Если это вызывает проблемы с производительностью, потому что у вас много данных Seed, то обычно довольно просто добавить проверки в метод Seed, которые запрашивают базу данных, чтобы определить, сколько работы необходимо выполнить, прежде чем ее выполнять.

person Arthur Vickers    schedule 31.05.2012
comment
Спасибо, Артур. Это было ясно, лаконично и именно то, что я искал. Я закончил тем, что изменил свое семя, чтобы предположить, что он будет запускаться каждый раз, но хорошо знать историю, стоящую за ним (которую я не смог найти). - person shox; 04.06.2012
comment
Тот факт, что начальный метод раньше запускался только при миграции, а теперь начальный метод запускается каждый раз, когда контекст используется впервые, очень сбивает с толку. Есть ли где-нибудь статья MSDN, в которой подробно описывается это изменение? - person lee_mcmullen; 28.08.2014

Я частично согласен с ответом Arthur Vickers, однако IMO Seed предназначен для DbMigrations, и я не хочу, чтобы метод Seed проверять все каждый раз, например Если у меня есть 4 миграции, мне нужно будет как-то проверить, какие данные должны быть заполнены, и это будет как минимум еще 4 обращения к базе данных. В случае, если вы все еще хотите, чтобы метод Seed запускался только тогда, когда применяются миграции, как и я, я пришел со своей собственной реализацией стратегии IDatabaseInitializer

public class CheckAndMigrateDatabaseToLatestVersion<TContext, TMigrationsConfiguration>
    : IDatabaseInitializer<TContext>
    where TContext : DbContext
    where TMigrationsConfiguration : DbMigrationsConfiguration<TContext>, new()
{
    public virtual void InitializeDatabase(TContext context)
    {
        var migratorBase = ((MigratorBase)new DbMigrator(Activator.CreateInstance<TMigrationsConfiguration>()));
        if (migratorBase.GetPendingMigrations().Any())
            migratorBase.Update();
    }
}
person Guillermo Ruffino    schedule 16.01.2015
comment
Спасибо, это именно то, что я искал. - person Jono; 05.05.2016

Другой вариант может заключаться в загрузке настраиваемого класса инициализатора db во время выполнения в методе seed. Затем производственное приложение может загрузить фиктивный инициализатор, а приложение разработчика может загрузить настоящий инициализатор. Вы можете использовать Unity / MEF

    // Unity Dependency Injection Prop
    [Dependency]
    property IMyInitializer initializer;

    protected override Seed(YourContextClass context)
    {
       initializer.Seed(context);
    }

Что-то такое. Затем вы должны переключить инициализаторы, как только у вас будет настроена БД в производственной среде, на фиктивный, который ничего не сделает.

person Gary Gaughan-Smith    schedule 14.10.2012