Применение миграций
После добавления миграций их необходимо развернуть и применить к базам данных. Существуют различные стратегии для этого, с некоторыми более подходящими для рабочих сред и других для жизненного цикла разработки.
Примечание.
Независимо от стратегии развертывания всегда проверяйте созданные миграции и тестируйте их перед применением к рабочей базе данных. Миграция может удалить столбец, когда намерение было переименовать его или может завершиться сбоем по различным причинам при применении к базе данных.
Скрипты 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()
.