Лучший способ пошагового заполнения данных в Entity Framework 4.3

Я использую Entity Framework 4.3 в существующей базе данных, и у меня есть несколько сценариев, которые я пытаюсь удовлетворить.

Во-первых, если я удаляю свою базу данных, я бы хотел, чтобы EF воссоздал ее с нуля - для этого я успешно использовал инициализатор базы данных CreateDatabaseIfNotExists.

Во-вторых, если я обновляю свою модель и база данных уже существует, я бы хотел, чтобы база данных обновлялась автоматически - я успешно использовал Entity Framework 4.3 Migrations для этого.

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

В некоторых примерах миграции EF я видел, как люди использовали функцию SQL() в методе UP миграции для создания начальных данных, но, если возможно, я бы предпочел использовать контекст для создания начальных данных (как вы видите в большинстве примеров инициализатора базы данных). мне кажется странным, что вы будете использовать чистый sql, когда вся идея EF абстрагируется от этого. Я пытался использовать контекст в методе UP, но по какой-то причине он не думал, что таблица, созданная в процессе миграции, существовала, когда я пытался добавить начальные данные непосредственно под вызовом для создания таблицы.

Любая мудрость высоко ценится.

2 ответа

Решение

Если вы хотите использовать сущности для заполнения данных, вы должны использовать Seed метод в вашей конфигурации миграции. Если вы генерируете свежий проект Enable-Migrations вы получите этот класс конфигурации:

internal sealed class Configuration : DbMigrationsConfiguration<YourContext>
{
    public Configuration()
    {
        AutomaticMigrationsEnabled = false;
    }

    protected override void Seed(CFMigrationsWithNoMagic.BlogContext context)
    {
        //  This method will be called after migrating to the latest version.

        //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
        //  to avoid creating duplicate seed data. E.g.
        //
        //    context.People.AddOrUpdate(
        //      p => p.FullName,
        //      new Person { FullName = "Andrew Peters" },
        //      new Person { FullName = "Brice Lambson" },
        //      new Person { FullName = "Rowan Miller" }
        //    );
        //
    }
}

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

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

public partial class SomeMigration : DbMigration
{
    public override void Up()
    {
        ...
        Sql("UPDATE ...");
        Sql("INSERT ...");
    }

    public override void Down()
    {
        ...
    }
}

Я бы не рекомендовал использовать Sql() звонки в вашем Up() метод, потому что (IMO) это действительно предназначено для фактического кода миграции, для которого нет встроенной функции, а не начального кода.

Мне нравится думать о начальных данных как о чем-то, что может измениться в будущем (даже если моя схема этого не сделает), поэтому я просто пишу "защитные" проверки вокруг всех моих вставок в начальную функцию, чтобы убедиться, что операция не сработала ранее.

Рассмотрим сценарий, в котором у вас есть таблица "Типы", которая начинается с 3 записей, но затем вы добавляете 4-ю. Вам не нужно "миграция", чтобы решить эту проблему.

С помощью Seed() также дает вам полный контекст для работы, что намного лучше, чем использование простых строк SQL в Sql() метод, который продемонстрировал Ладислав.

Кроме того, имейте в виду, что преимущество использования встроенных методов EF как для кода миграции, так и для исходного кода состоит в том, что ваши операции с базами данных остаются независимыми от платформы. Это означает, что ваши изменения схемы и запросы могут выполняться на Oracle, Postgre и т. Д. Если вы пишете реальный необработанный SQL, то вы потенциально необязательны.

Вы можете быть менее обеспокоены этим, поскольку 90% людей, использующих EF, будут использовать только SQL Server, но я просто добавлю его, чтобы дать вам другой взгляд на решение.

Другие вопросы по тегам