Присвоение начальных значений данных

Заполнение данных — это процесс заполнения базы данных исходным набором данных.

Это можно сделать несколькими способами в EF Core:

  • Данные начального значения модели
  • Настройка миграции вручную
  • Настраиваемая логика инициализации

Данные начального значения модели

В отличие от EF6, в EF Core начальные данные могут быть связаны с типом сущности в рамках конфигурации модели. Затем миграции EF Core могут автоматически вычислять операции вставки, обновления или удаления, которые необходимо применить при обновлении базы данных до новой версии модели.

Примечание.

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

В качестве примера это приведет к настройке начальных данных для следующих значений BlogOnModelCreating:

modelBuilder.Entity<Blog>().HasData(new Blog { BlogId = 1, Url = "http://sample.com" });

Чтобы добавить сущности, имеющие связь, необходимо указать значения внешнего ключа:

modelBuilder.Entity<Post>().HasData(
    new Post { BlogId = 1, PostId = 1, Title = "First post", Content = "Test 1" });

Если тип сущности имеет свойства в теневом состоянии анонимного класса, можно использовать для предоставления значений:

modelBuilder.Entity<Post>().HasData(
    new { BlogId = 1, PostId = 2, Title = "Second post", Content = "Test 2" });

Типы принадлежащих сущностей можно заполнить аналогичным образом:

modelBuilder.Entity<Post>().OwnsOne(p => p.AuthorName).HasData(
    new { PostId = 1, First = "Andriy", Last = "Svyryd" },
    new { PostId = 2, First = "Diego", Last = "Vega" });

Дополнительные сведения см. в полном примере проекта .

После добавления данных в модель следует использовать миграцию для применения изменений.

Совет

Если необходимо применить миграции в рамках автоматического развертывания, можно создать скрипт SQL, который можно предварительно просмотреть перед выполнением.

Кроме того, можно создать context.Database.EnsureCreated() новую базу данных, содержащую начальные данные, например для тестовой базы данных или при использовании поставщика в памяти или любой нереляционной базы данных. Обратите внимание, что если база данных уже существует, EnsureCreated() не обновит схему или начальные данные в базе данных. Для реляционных баз данных не следует вызывать EnsureCreated() , если планируется использовать миграции.

Ограничения начальных данных модели

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

  • Необходимо указать значение первичного ключа, даже если оно обычно создается базой данных. Он будет использоваться для обнаружения изменений данных между миграциями.
  • Если первичный ключ изменен каким-либо образом, будут удалены ранее затраченные данные.

Поэтому эта функция наиболее полезна для статических данных, которые, как ожидается, не изменяются вне миграции и не зависят от других компонентов базы данных, например ZIP-кодов.

Если сценарий включает в себя любой из следующих вариантов, рекомендуется использовать пользовательскую логику инициализации, описанную в последнем разделе:

  • Временные данные для тестирования
  • Данные, зависящие от состояния базы данных
  • Большие данные (начальные данные фиксируются в моментальных снимках миграции, и большие данные могут быстро привести к огромным файлам и снижению производительности).
  • Данные, необходимые для создания ключевых значений базой данных, включая сущности, использующие альтернативные ключи в качестве удостоверения.
  • Данные, требующие пользовательского преобразования (которые не обрабатываются преобразованиями значений), например хэширование паролей
  • Данные, требующие вызовов внешнего API, таких как ASP.NET роли Core Identity и создание пользователей

Настройка миграции вручную

При добавлении миграции изменения в указанные HasData данные преобразуются в вызовы InsertData(), UpdateData()и DeleteData(). Одним из способов обойти некоторые ограничения являются ручное добавление этих вызовов HasData или пользовательских операций в миграцию.

migrationBuilder.InsertData(
    table: "Blogs",
    columns: new[] { "Url" },
    values: new object[] { "http://generated.com" });

Настраиваемая логика инициализации

Простой и эффективный способ выполнения заполнения данных — использовать DbContext.SaveChanges() до начала выполнения основной логики приложения.

using (var context = new DataSeedingContext())
{
    context.Database.EnsureCreated();

    var testBlog = context.Blogs.FirstOrDefault(b => b.Url == "http://test.com");
    if (testBlog == null)
    {
        context.Blogs.Add(new Blog { Url = "http://test.com" });
    }

    context.SaveChanges();
}

Предупреждение

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

В зависимости от ограничений развертывания код инициализации можно выполнять разными способами:

  • Локальное выполнение приложения инициализации
  • Развертывание приложения инициализации с помощью основного приложения, вызов подпрограммы инициализации и отключение или удаление приложения инициализации.

Обычно это можно автоматизировать с помощью профилей публикации.