Подробности того, как реализованы миграции в EF Core, описаны в отдельной заметке. Здесь же разберёмся, как эти самые миграции применять.
Применение миграции — это обновление схемы данных конкретной БД. Если для разработки используется несколько стендов с разными БД, то. одни и те же миграции могут быть на каких-то стендах применены, на каких-то нет. На какие-то стенды они должны раскатываться автоматически, а на какие-то в ручном режиме.
Применить миграцию можно следующими способами:
- Из командной строки, командой dotnet ef database update. Можно указать название конкретной миграции, чтобы либо обновить не до самой последней, либо откатить назад: dotnet ef database update MigrationName. Выполнение этой команды приведёт к сборке проекта, подключению к БД (строка подключения будет взята из appsettings.json) и запросу к таблице __EFMigrationsHistory с тем, чтобы выяснить, нужно ли применять миграции и какие. Если какие-то миграции не применены, они тут же будут применены.
- Из Visual Studio, используя панель Package Manager Console: Update-Database или Update-Database MigrationName.
В обоих этих случаях нужно либо находиться в проекте с миграциями, либо дополнительными параметрами указывать соответствующие сборки и строки подключения к обновляемой БД.
Так же существует вариант генерации SQL-скрипта, который уже самостоятельно можно будет применить к нужной БД. Для его генерации через командную строку нужно добавить в команду параметр script: dotnet ef migrations script, а из Visual Studio использовать отдельную команду Script-Migration.
Автоматическое применение миграций
Но удобнее всего, когда приложение автоматически обновляет свою БД при запуске. Для этого нужно выполнить такой метод у вашего dbContext: dbContext.Database.MigrateAsync(). Так же через свойство Database можно получить список примененных миграций (то, что записано в таблице __MigrationsHistory), и список миграций, которые будут применены командой MigrateAsync().
Если вы делаете сервис asp.net core, вызов метода, применяющего миграции, можно добавить в Program.cs перед запуском хоста. Либо вынести этот код в отдельный фоновый сервис, который автоматически выполнится перед запуском хоста. Останется только добавить зависимость:
А весь остальной код убрать в сервис, который автоматически получит свои зависимости (например, логгер) и выполнится в нужный момент.
Использование IHostedService гарантирует, что метод StartAsync выполнится, когда хост будет готов к запуску, но до того, как он запустится, что исключит ситуацию, когда миграции ещё не применились, а приложение уже начало обрабатывать входящие запросы.
Если в вашем сценарии вы хотите, например, обновлять прод-сервер вручную, а автоматике доверять только тестовые сервера, можно добавить условие IsProduction():
Текущее значение environment берётся из переменной окружения ASPNETCORE_ENVIRONMENT, что позволяет реализовывать разное поведение для различных стендов (development, test и т.п.).