Содержание
До этого момента, при работе EF Core мы использовали так называемый подход «Code First» — то есть, вначале мы определяли модель и контекст данных, а затем создавали базу данных и работали с ней. Такой подход вполне логичен и широко используется в работе. Однако, может возникнуть ситуация, при которой нам необходимо подключиться к уже готовой базе. И в этом случае могут возникнуть серьезные трудности при подходе «Code First»
Проблема подключения к существующей базе данных
Самая главная проблема подключения к уже существующей базе данных — это затраты времени.
Когда база содержит всего одну таблицу, то, конечно, мы можем использовать уже испробованный поход — посмотреть поля таблицы, создать на их основе класс модели в C#, контекст и начат работу.
Однако, представим себе ситуацию, когда таблиц не одна, а, например, пятьдесят, определены внешние ключи и так далее. Возникает проблема — как описать все эти таблицы и ключи, используя классы C#. На такую работу могут уйти даже не дни, а недели работы.
Для таких ситуаций в EF Core может применяться подход «Database First», то есть, когда база данный первична и на её основе автоматически генерируются необходимые классы моделей и контекст данных. То есть, осуществляется Reverse Engineering.
Подключение к существующей базе MySQL
В предыдущей части мы уже разработали наше первое приложение Blazor Server для работы с MySQL. Давайте теперь воспользуемся созданной БД и напишем ещё одно приложение, в котором используем подход «Database First». Итак, создадим новое приложение Blazor Server:
И добавим в него следующие пакеты через менеджер пакетов NuGet:
- Microsoft.EntityFrameworkCore
- Microsoft.EntityFrameworkCore.Tools
- Pomelo.EntityFrameworkCore.MySql
Этих трех пакетов нам будет достаточно, чтобы провести reverse engineering нашей базы данных MySQL. Теперь, для реверса базы данных (создания необходимых классов C#) мы можем воспользоваться либо консолью PowerShell для разработчиков, либо консолью менеджера пакетов. Рассмотрим оба эти варианта.
Использования консоли менеджера пакетов
В Visual Studio в меню выбираем: Средства — Диспетчер пакетов NuGet — Консоль диспетчера пакетов
Теперь в этой консоли мы должны набрать команду следующего вида:
Scaffold-DbContext «строка_подключения» провайдер_БД
то есть, для нашего случая, команда должна выглядеть следующим образом:
Scaffold-DbContext "server=127.0.0.1;Port=3306;user=admin;password=test;database=users;" Pomelo.EntityFrameworkCore.MySql
строка подключения взята из первого приложения с EF Core. После ввода команды мы увидим следующие сообщения в консоли:
Желтым выделено предупреждение о том, что стоит защитить потенциально конфиденциальную информацию о подключении. В самом проекте (в корне) мы увидим два класса C# — модель и контекст данных:
Использование PowerShell
В меню Visual Studio выбираем: Средства — Командная строка — PowerShell для разработчиков:
Первая команда установить глобальный инструмент dotnet ef:
dotnet tool install --global dotnet-ef
После успешного выполнения команды вы увидите следующее сообщение в консоли:
Теперь используем это средство для реверса базы данных:
dotnet ef dbcontext scaffold "server=127.0.0.1;Port=3306;user=admin;password=test;database=users;" Pomelo.EntityFrameworkCore.MySql
В консоли мы увидим тоже самое сообщение, что и в предыдущем варианте работы через консоль менеджера пакетов.
Содержимое созданных классов C#
Посмотрим на содержимое созданных файлов. Модель данных получилась следующая:
public partial class User { public int Id { get; set; } public string? Name { get; set; } public string? Email { get; set; } public int Age { get; set; } }
Класс модели определен как частичный. Но, в целом, полностью соответствует тому, который мы создавали вручную. С контекстом данных всё немного иначе:
public partial class UsersContext : DbContext { public UsersContext() { } public UsersContext(DbContextOptions<UsersContext> options) : base(options) { } public virtual DbSet<User> Users { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) #warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263. => optionsBuilder.UseMySql("server=127.0.0.1;port=3306;user=admin;password=test;database=users", Microsoft.EntityFrameworkCore.ServerVersion.Parse("8.0.26-mysql")); protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder .UseCollation("utf8mb4_0900_ai_ci") .HasCharSet("utf8mb4"); modelBuilder.Entity<User>(entity => { entity.HasKey(e => e.Id).HasName("PRIMARY"); entity.ToTable("users"); }); OnModelCreatingPartial(modelBuilder); } partial void OnModelCreatingPartial(ModelBuilder modelBuilder); }
Здесь сразу в глаза бросается предупреждение о потенциально конфиденциальных данных (его можно безопасно удалить). Метод OnConfiguring
содержит настройки подключения с использованием конкретной версии сервера:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseMySql("server=127.0.0.1;port=3306;user=admin;password=test;database=users", Microsoft.EntityFrameworkCore.ServerVersion.Parse("8.0.26-mysql"));
В моем случае, это версия 8.0.26-mysql. EF Core правильно определила версию и, соответственно, эту же версию и использует для настройки подключения, но, лично мое мнение, лучше заменить конкретную версию на использование метода AutoDetect
, как мы это делали ранее. Ну и, конечно же, строку подключение убрать из исходного кода и поместить её на период разработки, хотя бы в файл конфигурации.
Далее, в методе OnModelCreating
производится настройка кодировок и ключей в моделях. В принципе, эту часть можно оставлять как есть.
Теперь, когда мы получили необходимые классы C# для работы с MySQL, мы можем зарегистрировать в нашем приложении Blazor Server фабрику контекстов, как мы это сделали в предыдущей части
builder.Services.AddDbContextFactory<UsersContext>();
и работать с базой.
using (var db = _db.CreateDbContext()) { List<User> users = db.Users.ToList(); }
При этом, так как в классе контекста данных у нас был переопределен метод OnConfiguring
, то при создании фабрики не требуется передавать в параметрах настройки подключения.
Итого
Скачать код проекта из GithubВ зависимости от ситуации, в EF Core могут использоваться два подхода в работе: 1) «Code First» в котором первичен код C# — описание модели, контекста и создание на основе этих данных таблиц БД. 2) «Database First» — в этом случае на первом месте стоит готовая база данных по которой мы генерируем необходимые классы C#, используя пакет Microsoft.EntityFrameworkCore.Tools в котором содержатся необходимые инструменты для реверс инжиниринга БД.