EF Core. Управление базой данных (миграции)

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

  1. Для работы с миграциями в EF Core необходимо установить пакет Microsoft.EntityFrameworkCore.Tools
  2. Чтобы продемонстрировать все шаги по работе с миграциями, запустим MySQL Workbench и удалим базу данных users, которая использовалась в нашем первом проекте.
  3. Изменим конструктор класса ApplicationContext следующим образом:
public ApplicationContext(DbContextOptions<ApplicationContext> options):base(options) 
{
    //_ = Database.EnsureCreated();
}
Если не закомменировать эту строку в конструкторе, то при использовании миграций EF Core мы получим ошибку

Теперь всё готово для демонстрации работы с миграциями в EF Core.

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

Для создания первой миграции EF Core необходимо выполнить следующую команду:

Visual StudioИнтерфейс командной строки .NET

Запускаем консоль менеджера пакетов NuGet и выполняем операцию:

Add-Migration InitialCreate

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

Build started…
Build succeeded.
To undo this action, use Remove-Migration.

Набираем в командной строке следующую команду

dotnet ef migrations add InitialCreate

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

Build started…
Build succeeded.
Done. To undo this action, use ‘ef migrations remove’

После выполнения команды на создание миграции в нашем проекте появится новая папка с названием Migrations, которая будет содержать два файла:

  • ХХХХХХХХХХХ_InitialCreate.cs — основной файл миграции, в котором будут содержаться все необходимые действия для применения изменений в БД
  • {Название_контекста}ModelSnapshot.cs — мгновенный снимок модели, который будет использован для создания следующей миграции. В нашем случае, это тфайл должен иметь название ApplicationContextModelSnapshot.cs

Применяем миграцию

Теперь нам необходимо применить созданную миграцию. Чтобы это сделать, необходимо выполнить следующую команду:

Visual StudioИнтерфейс командной строки .NET
PM> Update-Database

После выполнения этой операции, в консоли мы увидим следующие сообщения

Build started…
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.

Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы

dotnet ef database update

После выполнения этой операции, в консоли мы увидим следующие сообщения

Build started…
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.

Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы

После применения миграции мы можем убедиться, что была создана новая БД MySQL:

Новая БД MySQLПри этом, обратите внимание, что помимо таблицы users, EF Core также добавила ещё одну служебную таблицу (журнал) применения миграций под названием __efmigrationshistory. Вот как будет выглядеть содержимое журнала после применения первой миграции:

Содержимое журнала применения миграций EF Core

Обновление модели данных

Теперь представим, что наше приложение получило развитие и мы решили изменить нашу модель пользователя, добавив в неё ещё одно поле:

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; } //новое свойство - роль пользователя в системе
}

Если мы попытаемся теперь запустить приложение, то получим ошибку следующего содержания:

Microsoft.EntityFrameworkCore.Query[10100] An exception occurred while iterating over the results of a query for context type ‘EFCoreBlazor.ApplicationContext’. MySqlConnector.MySqlException (0x80004005): Unknown column ‘u.Role’ in ‘field list’

EF Core обнаружила, что наша модель содержит неизвестное поле Role, то есть нага модель и рабочая база данных не синхронизированы, поэтому необходимо добавить новый столбец в схему базы данных. Чтобы это сделать, создадим новую миграцию.

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

Создаем новую миграцию:

Visual StudioИнтерфейс командной строки .NET
Add-Migration AddUserRole

здесь AddUserRole — это название новой миграции (может быть любым). После создания новой миграции, в консоли увидим следующее сообщение:

Build started…
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 started…
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’

После создания новой миграции в проект будет добавлен новый файл:

EF Core MigrationОбновление базы данных после внесения изменений в модель

Снова вызываем команду обновления базы данных:

Visual StudioИнтерфейс командной строки .NET
PM> Update-Database

После выполнения этой операции, в консоли мы увидим следующие сообщения

Build started…
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.

Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы

dotnet ef database update

После выполнения этой операции, в консоли мы увидим следующие сообщения

Build started…
Build succeeded.
Microsoft.EntityFrameworkCore.Database.Command[20101] …. Done.

Вместо многоточия в консоли вы увидите какие команды выполнялись EF Core и какие файлы буди для этого задействованы

Теперь наша база данных и модель синхронизированы. Убедиться в этом можно, посмотрев схему БД в MySQL Workbench:

Синхронизация базы данных и модели в EF Core

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

Создание SQL-скрипта для обновления базы данных

Иногда нам необходимо не применять миграцию моментально, а использовать для синхронизации SQL-скрипт. Инструменты EF Core позволяют сформировать скрипт по миграции. Чтобы создать SQL-скрипт необходимо выполнить следующую операцию:

Visual StudioИнтерфейс командной строки .NET
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;} 
    }
}

и создал новую миграцию, используя приведенное выше пошаговое руководство:

Новая миграция EF Core

Теперь применим эту миграцию при создании контекста данных. Для этого перепишем конструктор класса ApplicationContext следующим образом:

public ApplicationContext(DbContextOptions<ApplicationContext> options):base(options) 
{
    Database.Migrate();//применяем последнюю миграцию
 //   _ = Database.EnsureCreated();
}

Теперь запустим наше приложение и убедимся, что миграция была применена успешно — для этого достаточно заглянуть в консоль приложения:

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

Итого

Скачать код проекта из Github

Сегодня мы рассмотрели в общих чертах применение миграций в EF Core для синхронизации базы данных и модели в EF Core. Конечно, мы рассмотрели далеко не все возможности по работе с миграциями, но полученных знаний будет пока вполне достаточно, чтобы продолжить изучение работы EF Core в C#. В дальнейшем, мы рассмотрим более подробно работу с миграциями в EF Core, но уже опираясь на полученный сегодня опыт.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии