Вопрос по entity-framework, entity-framework-4.3, ef-code-first, ef-migrations – Путаница в EF Auto Миграции и посев - посев при каждом запуске программы

42

Я недавно изменил приложение с использованием следующего для dev:

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 ранее с заполнением в db (DropCreateDatabaseIfModelChanges).

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

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

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

Ваш Ответ

3   ответа
16

Я несколько согласен сАртур Виккерс Ответ, однако 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();
    }
}
Отличное решение, работает как по волшебству.
Спасибо, это было именно то, что я искал.
60

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

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

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

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

Спасибо Артур. Это было ясно, кратко и именно то, что я искал. Я закончил тем, что изменил свое семя, чтобы предположить, что оно будет работать каждый раз, но хорошо знать историю, стоящую за ним (которую я не смог найти). shox
Тот факт, что метод seed использовался только тогда, когда произошла миграция, и теперь метод seed запускается каждый раз, когда контекст используется впервые, очень сбивает с толку. Есть ли где-нибудь статья MSDN, в которой подробно описано это изменение?
2

затора БД во время выполнения внутри метода seed. Приложение Production может затем загрузить фиктивный инициализатор, тогда как приложение dev может загрузить реальный инициализатор. Вы можете использовать Unity / MEF

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

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

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

Похожие вопросы