Лучший способ пошагового семени данных в Entity Framework 4.3
Я использую Entity Framework 4.3 в существующей базе данных, и у меня есть несколько сценариев, которые я пытаюсь удовлетворить.
Во-первых, если я удалю свою базу данных, я бы хотел, чтобы EF воссоздал, если с нуля - я успешно использовал для этого инициализатор базы данных CreateDatabaseIfNotExists.
Во-вторых, если я обновляю свою модель, и база данных уже существует, я бы хотел, чтобы база данных обновлялась автоматически - я успешно использовал Entity Framework 4.3. Миграции для этого.
Итак, вот мой вопрос. Скажем, я добавляю новую таблицу в свою модель, которая требует некоторых ссылочных данных, что это лучший способ обеспечить, чтобы эти данные создавались как при запуске базы данных, так и при миграции. Мое желание состоит в том, что данные создаются, когда я создаю db с нуля, а также когда база данных обновляется в результате миграции.
В некоторых примерах миграции EF я видел, как люди используют функцию SQL() в методе UP для переноса данных для создания исходных данных, но, если возможно, я предпочел бы использовать контекст для создания исходных данных (как вы видите в большинстве баз данных примеры инициализации), поскольку мне кажется странным, что вы использовали бы чистый sql, когда вся идея EF абстрагирует это. Я попытался использовать контекст в методе UP, но по какой-то причине он не думал, что таблица, созданная при миграции, существовала, когда я пытался добавить данные семян непосредственно под вызовом для создания таблицы.
Любая мудрость очень ценится.
Ответы
Ответ 1
Если вы хотите использовать сущности для высева данных, вы должны использовать метод 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()
{
...
}
}
Ответ 2
Я бы не рекомендовал использовать вызовы Sql()
в вашем методе Up()
, потому что (IMO) это действительно предназначено для реального кода миграции, для которого нет встроенной функции, а не кода семени.
Мне нравится думать о данных семян как о чем-то, что может измениться в будущем (даже если моя схема не работает), поэтому я просто пишу "защитные" проверки всех моих вставок в функции семени, чтобы убедиться, что операция ранее не срабатывал.
Рассмотрим сценарий, в котором у вас есть таблица "Типы", которая начинается с 3 записей, но затем вы добавите четвертый. Для этого вам не требуется "миграция".
Использование Seed()
также дает вам полный контекст для работы, что намного лучше, чем использование простых строк sql в методе Sql()
, который продемонстрировал Ладислав.
Кроме того, имейте в виду, что преимущество использования встроенных методов EF для кода перехода и кода семени заключается в том, что ваши операции с базой данных остаются нейтральными по отношению к платформе. Это означает, что ваши изменения схемы и запросы могут выполняться на Oracle, Postgre и т.д. Если вы напишете фактический необработанный SQL, тогда вы потенциально заблокируете себя без необходимости.
Вы можете быть менее обеспокоены этим, поскольку 90% людей, использующих EF, будут когда-либо сталкиваться с SQL Server, но я просто бросаю его туда, чтобы дать вам другую перспективу в решении.