Поделиться через


Применение миграций

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

Примечание.

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

Скрипты SQL

Рекомендуемый способ развертывания миграции в рабочую базу данных — создание скриптов SQL. К преимуществам этой стратегии относятся следующие преимущества:

  • Скрипты SQL можно проверить для точности; Это важно, так как применение изменений схемы к рабочим базам данных является потенциально опасной операцией, которая может привести к потере данных.
  • В некоторых случаях скрипты можно настроить в соответствии с конкретными потребностями рабочей базы данных.
  • Скрипты SQL можно использовать в сочетании с технологией развертывания и даже создавать в рамках процесса CI.
  • Скрипты SQL можно предоставлять в DBA и управлять и архивировать отдельно.

Базовое использование

Ниже приводится создание скрипта SQL из пустой базы данных в последнюю миграцию:

dotnet ef migrations script

С from (в подразумеваемую миграцию)

В следующем примере создается скрипт SQL из данной миграции в последнюю миграцию.

dotnet ef migrations script AddNewTables

С from и to

В следующем примере создается скрипт SQL из указанной from миграции на указанную to миграцию.

dotnet ef migrations script AddNewTables AddAuditTable

Для создания скрипта отката можно использовать значение from, более новое, чем to.

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

Обязательно учитывайте возможные сценарии потери данных.

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

  • Миграция from должна быть последней миграцией, применяемой к базе данных перед выполнением скрипта. Если не было применено ни одной миграции, укажите 0 (это значение по умолчанию).
  • Миграция to является последней миграцией, применяемой к базе данных после выполнения скрипта. По умолчанию она является последней миграцией в проекте.

Скрипты Idempotent SQL

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

Ниже приводится идемпотентная миграция:

dotnet ef migrations script --idempotent

Программы командной строки

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

  • Команды SQL применяются непосредственно средством, не предоставляя разработчику возможность проверять или изменять их. Это может быть опасно в рабочей среде.
  • Пакет SDK для .NET и средство EF должны быть установлены на рабочих серверах и требуют исходного кода проекта.

Следующие обновления базы данных до последней миграции:

dotnet ef database update

Следующие обновления базы данных до заданной миграции:

dotnet ef database update AddNewTables

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

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

Обязательно учитывайте возможные сценарии потери данных.

Дополнительные сведения о применении миграции с помощью средств командной строки см. в справочнике по средствам EF Core.

Наборы

Пакеты миграции — это исполняемые файлы с одним файлом, которые можно использовать для применения миграций к базе данных. Они устраняют некоторые недостатки скрипта SQL и средств командной строки:

  • Выполнение скриптов SQL требует дополнительных средств.
  • Обработка транзакций и поведение по ошибке для этих средств являются несогласованными и иногда непредвиденными. Это может оставить базу данных в неопределенном состоянии, если при применении миграций возникает сбой.
  • Пакеты можно создавать в рамках процесса CI и легко выполнять позже в процессе развертывания.
  • Пакеты могут выполняться без установки пакета SDK для .NET или средства EF (или даже среды выполнения .NET, когда они не содержатся) и не требуют исходного кода проекта.

Ниже приводится создание пакета:

dotnet ef migrations bundle

Ниже приводится создание автономного пакета для Linux:

dotnet ef migrations bundle --self-contained -r linux-x64

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

efbundle

Результирующий исполняемый файл по умолчанию называется efbundle . Его можно использовать для обновления базы данных до последней миграции. Это эквивалентно выполнению dotnet ef database update или Update-Database.

Аргументы:

Аргумент Description
<MIGRATION> Целевая миграция. Если значение "0", все миграции будут отменены. По умолчанию используется последняя миграция.

Параметры:

Вариант Короткие Description
--connection <CONNECTION> Строка подключения к базе данных. Значение по умолчанию указано в AddDbContext или OnConfiguring.
--verbose -v Отображение подробных выходных данных.
--no-color Не цветируйте выходные данные.
--prefix-output Выходные данные префикса с уровнем.

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

.\efbundle.exe --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;User ID=myUsername;Password={;'$Credential;'here'}'

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

Не забудьте скопировать appsettings.json вместе с пакетом. Пакет зависит от наличия appsettings.json в каталоге выполнения.

Пример пакета миграции

Пакет должен включать в себя миграции. Они создаются, dotnet ef migrations add как описано в разделе "Создание первой миграции". После того как миграции будут готовы к развертыванию, создайте пакет с помощью dotnet ef migrations bundle. Например:

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

Выходные данные представляют собой исполняемый файл, подходящий для целевой операционной системы. В этом случае это Windows x64, поэтому efbundle.exe находится в локальной папке. При выполнении этого исполняемого файла применяются содержащиеся в нем миграции:

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903083845_MyMigration'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Как и dotnet ef database update Update-Databaseпри использовании, миграции применяются к базе данных только в том случае, если они еще не применены. Например, при повторном выполнении одного и того же пакета ничего не происходит, так как нет новых миграций для применения.

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
No migrations were applied. The database is already up to date.
Done.
PS C:\local\AllTogetherNow\SixOh>

Однако если в модель были внесены изменения, и с помощью dotnet ef migrations add созданы дополнительные миграции, они могут быть объединены в новый исполняемый файл и готовы к применению. Например:

PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add SecondMigration
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations add Number3
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS C:\local\AllTogetherNow\SixOh> dotnet ef migrations bundle --force
Build started...
Build succeeded.
Building bundle...
Done. Migrations Bundle: C:\local\AllTogetherNow\SixOh\efbundle.exe
PS C:\local\AllTogetherNow\SixOh>

Совет

Этот --force параметр можно использовать для перезаписи существующего пакета новым.

При выполнении этого нового пакета к базе данных применяются следующие две новые миграции:

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

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

PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe --connection "Data Source=(LocalDb)\MSSQLLocalDB;Database=SixOhProduction"
Applying migration '20210903083845_MyMigration'.
Applying migration '20210903084526_SecondMigration'.
Applying migration '20210903084538_Number3'.
Done.
PS C:\local\AllTogetherNow\SixOh>

Примечание.

На этот раз все три миграции были применены, так как ни одна из них еще не была применена к рабочей базе данных.


Применение миграции во время выполнения

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

  • Для версий EF до 9, если запущено несколько экземпляров приложения, оба приложения могут попытаться применить миграцию одновременно и завершиться сбоем (или хуже, привести к повреждению данных).
  • Аналогичным образом, если приложение обращается к базе данных во время миграции другого приложения, это может привести к серьезным проблемам.
  • Приложение должно иметь повышенный доступ для изменения схемы базы данных. Обычно рекомендуется ограничить разрешения базы данных приложения в рабочей среде.
  • Важно иметь возможность отката примененной миграции в случае проблемы. Другие стратегии обеспечивают это легко и вне поля.
  • Команды SQL применяются непосредственно программой, не предоставляя разработчику возможность проверять или изменять их. Это может быть опасно в рабочей среде.

Чтобы применить миграции программным способом, вызовите context.Database.Migrate(). Например, обычное приложение ASP.NET может выполнять следующие действия:

public static void Main(string[] args)
{
    var host = CreateHostBuilder(args).Build();

    using (var scope = host.Services.CreateScope())
    {
        var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
        db.Database.Migrate();
    }

    host.Run();
}

Обратите внимание, что Migrate() строится на основе IMigrator службы, которая может использоваться для более сложных сценариев. Для доступа к нему используйте myDbContext.GetInfrastructure().GetService<IMigrator>().

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

  • Тщательно рассмотрите возможность использования этого подхода в рабочей среде. Опыт показал, что простота этой стратегии развертывания перевешивает создаваемые проблемы. Вместо этого рекомендуется создавать скрипты SQL из миграций.
  • Не вызывайте EnsureCreated() перед Migrate(). EnsureCreated() обходит миграции, чтобы создать схему, что приводит к сбою Migrate().