Лучший способ пошагового заполнения данных в Entity Framework 4.3 - PullRequest
41 голосов
/ 18 февраля 2012

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

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

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

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

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

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

Ответы [ 2 ]

55 голосов
/ 18 февраля 2012

Если вы хотите использовать сущности для заполнения данных, вы должны использовать метод 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()
    {
        ...
    }
}
32 голосов
/ 31 мая 2012

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

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

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

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

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

...