Рекомендуемый способ очистки старых миграций Entity Framework Core - PullRequest
3 голосов
/ 28 июня 2019

После некоторой разработки нашего приложения мы накопили немало миграций базы данных EFCore. Поскольку EFCore добавляет моментальный снимок всей модели базы данных к каждой миграции, этот код добавляет довольно много. После анализа около 80% нашего времени компиляции тратится на миграцию (компиляция + анализаторы Roslyn).

Итак, пришло время очистить некоторые старые миграции! Но какой лучший способ сделать это? Официальных указаний по этому поводу не существует ...

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

Что я пробовал:

  1. Кажется, что ядерный вариант - удалить все миграции и снимок модели и создать новую начальную миграцию. Хотя это нормально, это кажется немного опасным. При таком подходе мы должны быть очень осторожными, чтобы каждая часть схемы базы данных была частью модели кода. Например, мы столкнулись с одним крайним случаем: EFCore еще не поддерживает проверенные ограничения. Поэтому мы добавили проверенное ограничение в миграцию, но не модель кода. Поэтому при создании новой начальной миграции проверяемое ограничение не было его частью.

  2. В качестве эксперимента я попытался удалить снимок модели из всех старых миграций, поскольку снимки составляют 90% кода, что приводит к длительному времени компиляции. Я полагал, что EFCore использует снимок только в качестве инструмента сравнения для новой миграции. Однако после удаления снимка старые миграции больше не выполнялись при запуске в новой базе данных.

Так есть ли лучший способ выполнить то, что я хочу?

1 Ответ

0 голосов
/ 04 июля 2019

Хорошо, с тех пор как я задал этот вопрос, я довольно много экспериментировал с этим.

На данный момент, кажется, лучший способ сделать это - вариант 1. Вариант 2 был бы намного лучше, но до тех пор, пока эта функция EFCore не будет реализована, это не очень возможно для моего варианта использования (поддержка существующих БД с миграциями на них и поддерживающие пустые БД).

Вариант 1 также имеет несколько ловушек, на которые я наткнулся (возможно, даже больше, на которые я не наткнулся). Вот как я это сделал:

Создать новую начальную миграцию:

  1. Убедитесь, что все ваши существующие миграции были применены к вашей базе данных. Мы создадим новую начальную миграцию, поэтому миграции, которые не были применены, будут потеряны.
  2. Удалите старые файлы миграции EFCore и файл снимка базы данных.
  3. Создать новую начальную миграцию из текущего состояния вашей базы данных. (Например, через dotnet ef migrations add Initial-PostCleanup.)

Эта новая миграция совместима только с новыми базами данных, так как она создаст все таблицы (и потерпит неудачу, если какие-либо таблицы, ограничения и т. Д. Уже существуют). Итак, теперь мы собираемся сделать эту миграцию совместимой с существующей базой данных:

  1. Создайте сценарий SQL для новой начальной миграции с помощью dotnet ef migrations script -o script.sql.
  2. Удалить первую транзакцию (до первой GO), которая создает таблицу __EFMigrationsHistory:
IF OBJECT_ID(N'[__EFMigrationsHistory]') IS NULL
BEGIN
    CREATE TABLE [__EFMigrationsHistory] (
        [MigrationId] nvarchar(150) NOT NULL,
        [ProductVersion] nvarchar(32) NOT NULL,
        CONSTRAINT [PK___EFMigrationsHistory] PRIMARY KEY ([MigrationId])
    );
END;

GO
  1. Удалить последнюю транзакцию, которая вставляет новую запись в таблицу __EFMigrationsHistory:
INSERT INTO [__EFMigrationsHistory] ([MigrationId], [ProductVersion])
VALUES (N'20190704144924_Initial-PostCleanup', N'2.2.4-servicing-10062');

GO
  1. Удалить GO команды, так как мы поместим скрипт create в оператор IF:
    Заменить GO\r\n\r\n ничем.
  2. Теперь откройте файл миграции (файл C #, а не файл sql) и замените метод Up следующим:
protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.Sql(@"
DECLARE @migrationsCount INT = (SELECT COUNT(*) FROM [dbo].[__EFMigrationsHistory])
IF @migrationsCount = 0
BEGIN
    % PASTE YOUR EDITED SQL SCRIPT HERE %
END
");
}

Готово! Все должно работать сейчас!

Обязательно сравните схему базы данных и данные до и после для новой базы данных. Все, что не является частью, если ваша модель EF Code не является частью новой базы данных.

...