Содержание
Миграции — это еще один способ управления базой данных в EF Core, который является предпочтительным при развитии уже готового проекта. В прошлой части руководства мы рассмотрели один из способов управления базой данных (с использованием методов Ensure
/Ensure
), который удобно использовать при разработке и прототипировании приложения. Сегодня же мы рассмотрим использование миграций в EF Core.
Когда необходимо использование миграций
Большинство реальных проектов так или иначе развиваются — добавляются новые функции, добавляются новые типы сущностей и т.д. При добавлении или изменении новых сущностей или свойств схемы базы данных мы должны соответствующим образом применить эти изменения в нашем проекте. Функция миграции в EF Core позволяет последовательно применять изменения схемы к базе данных, чтобы синхронизировать ее с моделью данных в приложении без потери существующих данных.
В общем миграции EF Core работают следующим образом:
- при изменении модели данных разработчик использует средства EF Core, чтобы добавить соответствующую миграцию с описанием обновлений, необходимых для синхронизации схемы базы данных.
- EF Core сравнивает текущую модель с моментальным снимком старой модели для определения различий и создает исходные файлы миграции.
- Созданную миграцию можно применять к базе данных различными способами. EF Core записывает все примененные миграции в специальную таблицу журнала, из которой будет ясно, какие миграции были применены, а какие нет.
Пошаговое руководство использования миграций в EF Core
Для рассмотрения работы с миграциями воспользуемся нашим первым приложением Blazor Server с EF Core. На данный момент наш проект содержит следующую модель:
namespace EFCoreBlazor.Models { public class User { public int Id { get; set; } public string? Name { get; set; } public string? Email { get; set; } public int Age { get; set; } } }
и контекст базы данных:
using Microsoft.EntityFrameworkCore; using EFCoreBlazor.Models; namespace EFCoreBlazor { public class ApplicationContext: DbContext { public DbSet<User> Users { get; set; } public ApplicationContext(DbContextOptions<ApplicationContext> options):base(options) { _ = Database.EnsureCreated(); } protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<User>().HasData(new User() {Id=1, Name="Джон Сноу", Age=35, Email="winterfall@throne.com"}); } } }
Предварительная подготовка проекта
Выполним последовательно следующие шаги по предварительной подготовке к работе с миграциями в EF Core.
- Для работы с миграциями в EF Core необходимо установить пакет Microsoft.EntityFrameworkCore.Tools
- Чтобы продемонстрировать все шаги по работе с миграциями, запустим MySQL Workbench и удалим базу данных
users
, которая использовалась в нашем первом проекте. - Изменим конструктор класса
ApplicationContext
следующим образом:
public ApplicationContext(DbContextOptions<ApplicationContext> options):base(options) { //_ = Database.EnsureCreated(); }
Теперь всё готово для демонстрации работы с миграциями в EF Core.
Создаем первую миграцию
Для создания первой миграции EF Core необходимо выполнить следующую команду:
Запускаем консоль менеджера пакетов NuGet и выполняем операцию:
Add-Migration InitialCreate
здесь InitialCreate
— это название миграции. После успешного выполнения операции вы увидите в консоли следующее сообщение:
Build succeeded.
To undo this action, use Remove-Migration.
Набираем в командной строке следующую команду
dotnet ef migrations add InitialCreate
здесь InitialCreate
— это название миграции. После успешного выполнения операции вы увидите в консоли следующее сообщение:
Build succeeded.
Done. To undo this action, use ‘ef migrations remove’
После выполнения команды на создание миграции в нашем проекте появится новая папка с названием Migrations, которая будет содержать два файла:
- ХХХХХХХХХХХ_InitialCreate.cs — основной файл миграции, в котором будут содержаться все необходимые действия для применения изменений в БД
- {Название_контекста}ModelSnapshot.cs — мгновенный снимок модели, который будет использован для создания следующей миграции. В нашем случае, это тфайл должен иметь название ApplicationContextModelSnapshot.cs
Применяем миграцию
Теперь нам необходимо применить созданную миграцию. Чтобы это сделать, необходимо выполнить следующую команду:
PM> Update-Database
После выполнения этой операции, в консоли мы увидим следующие сообщения
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.
Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы
dotnet ef database update
После выполнения этой операции, в консоли мы увидим следующие сообщения
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.
Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы
После применения миграции мы можем убедиться, что была создана новая БД MySQL:
При этом, обратите внимание, что помимо таблицы users, EF Core также добавила ещё одну служебную таблицу (журнал) применения миграций под названием
__efmigrationshistory
. Вот как будет выглядеть содержимое журнала после применения первой миграции:
Обновление модели данных
Теперь представим, что наше приложение получило развитие и мы решили изменить нашу модель пользователя, добавив в неё ещё одно поле:
public class User { public int Id { get; set; } public string? Name { get; set; } public string? Email { get; set; } public int Age { get; set; } public string? Role { get; set; } //новое свойство - роль пользователя в системе }
Если мы попытаемся теперь запустить приложение, то получим ошибку следующего содержания:
EF Core обнаружила, что наша модель содержит неизвестное поле Role
, то есть нага модель и рабочая база данных не синхронизированы, поэтому необходимо добавить новый столбец в схему базы данных. Чтобы это сделать, создадим новую миграцию.
Создание второй и последующих миграций
Создаем новую миграцию:
Add-Migration AddUserRole
здесь AddUserRole
— это название новой миграции (может быть любым). После создания новой миграции, в консоли увидим следующее сообщение:
Build succeeded.
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
To undo this action, use Remove-Migration.
dotnet ef migrations add AddUserRole
здесь AddUserRole
— это название новой миграции (может быть любым). После создания новой миграции, в консоли увидим следующее сообщение:
Build succeeded.
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
Done. To undo this action, use ‘ef migrations remove’
После создания новой миграции в проект будет добавлен новый файл:
Обновление базы данных после внесения изменений в модель
Снова вызываем команду обновления базы данных:
PM> Update-Database
После выполнения этой операции, в консоли мы увидим следующие сообщения
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.
Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы
dotnet ef database update
После выполнения этой операции, в консоли мы увидим следующие сообщения
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.
Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы
Теперь наша база данных и модель синхронизированы. Убедиться в этом можно, посмотрев схему БД в MySQL Workbench:
Таким образом, по мере развития модели данных мы можем создавать миграции данных и синхронизировать модель и базу данных без потери данных.
Создание SQL-скрипта для обновления базы данных
Иногда нам необходимо не применять миграцию моментально, а использовать для синхронизации SQL-скрипт. Инструменты EF Core позволяют сформировать скрипт по миграции. Чтобы создать SQL-скрипт необходимо выполнить следующую операцию:
Script-Migration
После выполнения операции в редакторе кода Visual Studio появится файл SQL-скрипта, созданного по последней миграции
dotnet ef migrations script
После выполнения операции в редакторе кода Visual Studio появится файл SQL-скрипта, созданного по последней миграции
После того, как будет создан файл SQL-скрипта, мы можем его сохранить и использовать вручную в том же MySQL Workbench для синхронизации базы данных и модели Ef Core.
Применение миграций в коде C#
Также, мы можем применять созданные миграции непосредственно во время выполнения приложения. Для демонстрации этой возможности и добавил в модель ещё одно поле:
namespace EFCoreBlazor.Models { public class User { ... public DateTime? CreatedAt { get; set;} } }
и создал новую миграцию, используя приведенное выше пошаговое руководство:
Теперь применим эту миграцию при создании контекста данных. Для этого перепишем конструктор класса ApplicationContext
следующим образом:
public ApplicationContext(DbContextOptions<ApplicationContext> options):base(options) { Database.Migrate();//применяем последнюю миграцию // _ = Database.EnsureCreated(); }
Теперь запустим наше приложение и убедимся, что миграция была применена успешно — для этого достаточно заглянуть в консоль приложения:
Итого
Скачать код проекта из GithubСегодня мы рассмотрели в общих чертах применение миграций в EF Core для синхронизации базы данных и модели в EF Core. Конечно, мы рассмотрели далеко не все возможности по работе с миграциями, но полученных знаний будет пока вполне достаточно, чтобы продолжить изучение работы EF Core в C#. В дальнейшем, мы рассмотрим более подробно работу с миграциями в EF Core, но уже опираясь на полученный сегодня опыт.