Содержание
Первое приложение, использующее EF Core будет консольным. В нем мы немного познакомимся с ORM-технологией, лежащей в основе EF Core. Также, это приложение поможет нам, в дальнейшем, увидеть некоторые особенности, использования EF Core с другими технологиями, например, с Blazor Server.
Предварительная настройка
Как и было сказано во введении, все примеры в руководстве по EF Core будут использовать MySQL. Поэтому, для работы нам потребуется зарегистрироваться на сайте mysql.com, скачать и установить необходимые инструменты для работы c MySQL. Для работы с базами данных я буду использовать MySQL Workbench. Для начала создадим новое подключение к базе данных MySQL. Для этого, находясь на главной странице MySQL Workbench необходимо нажать кнопку «Setup new connection»:
В появившемся окне нам необходимо будет задать название нового соединения, метод доступа и другие параметры нового соединения. Я задал следующие параметры соединения:
- Connection name: efcore
- Connection Method: Standard (TCP/IP)
- Host Name: 127.0.0.1
- Port: 3306
- UserName: admin
- Password: test
- Default Schema: не задано (при необходимости, можем определить это свойство позднее)
Теперь необходимо кликнуть левой кнопкой мыши по созданному соединению
Подключившись к MySQL нам необходимо создать новую схему (базу данных MySQL)
Назовем нашу первую БД users
и все остальные настройки новой схемы оставим по умолчанию:
После того, как нажмем Apply, MySQL Workbench ещё раз в отдельном окне попросит подтвердить создание новой схемы — подтверждаем. После этого, в списке Schemas появится новая пока ещё пустая база данных:
На этом предварительная подготовка к созданию первого приложения с EF Core закончена. Теперь перейдем в Visual Studio и напишем наше приложение.
Создание консольного приложения с EF Core и MySQL
Итак, создадим новое консольное приложение в Visual Studio:
Чтобы начать работать с EF Core и MySQL нам необходимо установить все необходимые пакеты. Для этого воспользуемся менеджером пакетов NuGet. Первый пакет — Microsoft.EntityFrameworkCore:
Этот пакет добавит в наш проект основной функционал EF Core. Чтобы мы могли работать в EF Core с MySQL, необходимо установить пакет, содержащий провайдер для этой базы данных. В перечне всех поставщиков баз данных на сайте Microsoft нам рекомендуется использовать провайдер, содержащийся в пакете Pomelo.EntityFrameworkCore.MySql. Устанавливаем этот пакет:
Теперь все пакеты установлены и можно приступать к разработке логики нашего приложения.
Модель данных
EF Core использует модель метаданных для описания и сопоставления типов сущностей приложения с базой данных. По сути, моделью данных может выступать как один класс C#, так и группа классов, которые могут быть как связаны между собой, так и быть независимыми друг от друга. Так как мы вначале создали БД с именем users, то, соответственно, первым классом, описывающим модель данных, у нас будет класс User
:
namespace EFCoreApp.Models { public class User { public int Id { get; set; } public string? Name { get; set; } public string? Email { get; set; } public int Age { get; set; } } }
Как видите, наша модель — это обычный класс C#. Однако, так как объекты этого класса будут выступать сущностями EF Core, у класса определено свойство Id
, которое будет выступать в качестве уникального ключа. Каждое свойство нашего класса будет в дальнейшем сопоставлено с отдельным столбцом таблицы БД. По умолчанию, при генерации таблиц БД EF Core в качестве первичных ключей рассматривает свойства с именами Id
или с именами вида [Имя_класса]Id
. То есть, в нашем случае, мы могли бы определить свойство UserId
и в EF Core это свойство использовалось бы по умолчанию как первичный ключ.
Создание контекста данных
Для взаимодействия с базой данных в EF Core используются специальный классы — контексты данных, которые наследуются от класса DbContext
. Поэтому, создадим такой класс и назовем его ApplicationContext
:
using Microsoft.EntityFrameworkCore; using EFCoreApp.Models; using Pomelo.EntityFrameworkCore.MySql; namespace EFCoreApp { public class ApplicationContext: DbContext { private const string _connection = @"server=127.0.0.1;Port=3306;user=admin;password=test;database=users"; public DbSet<User> Users { get; set; } public ApplicationContext() { _ = Database.EnsureCreated(); } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseMySql(_connection, ServerVersion.AutoDetect(_connection)); } } }
Рассмотрим по порядку, что содержит наш класс и как он работает. Во-первых, внутри класса мы определили константу, содержащую строку подключения к MySQL:
private const string _connection = @"server=127.0.0.1;Port=3306;user=admin;password=test;database=users";
Параметры подключения, которые мы использовали — представлены в разделе выше.
Далее, мы определили свойство:
public DbSet <User> Users { get; set; };
DbSet
— это, как и DbContext
, специальный класс, используемый в EF Core для хранения набора сущностей определенного класса. В нашем случае, модель состоит всего из одного класса, поэтому и свойство мы определили одно.
Далее, мы переопределили метод OnConfiguring
класса DbContext
. В этом методе мы настраиваем подключение к базе данных:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseMySql(_connection, ServerVersion.AutoDetect(_connection)); }
В этом методе мы используем параметр optionsBuilder
класса DbContextOptionsBuilder
для настройки подключения к MySQL. Метод UseMySQL
имеет несколько переопределенных версий и, в нашем случае, принимает два параметра: первый — строка подключения и второй — версия сервера MySQL. Так как версия сервера MySQL может измениться или же мы вовсе можем не знать с какой версией сервера мы будем в дальнейшем работать, то для получения значения этого параметра мы использовали статический метод класса ServerVersion.AutoDetect
, который и определит за нас версию сервера.
Так как на момент подключения к БД её в принципе может не существовать, то в конструкторе нашего класса мы используем метод Database.EnsureCreated()
, который проверяет наличие базы данных и, при необходимости, создает её:
public ApplicationContext() { _ = Database.EnsureCreated(); }
Создав контекст данных, можно переходить далее. Наполним нашу базу данных начальными данными
Присвоение начальных данных
Самый простой способ наполнить нашу базу начальными данными — это добавить эти данные до начала основной логики приложения. Например, это можно сделать следующим образом (в файле Program.cs нашего консольного приложения):
using EFCoreApp.Models; namespace EFCoreApp { internal class Program { static void Main(string[] args) { using var db = new ApplicationContext(); if (db.Users.Any() == false) //нет никаких данных в БД { //создаем нового пользователя User user = new() { Name = "admin", Age = 30, Email = "admin@corp.gov" }; //добавляем запись в БД db.Users.Add(user); db.SaveChanges(); } //получаем всех пользователей из БД List<User> users = db.Users.ToList(); foreach (User user in users) { Console.WriteLine($"{user.Id} {user.Name} {user.Email} {user.Age}"); } } } }
Опять же, рассмотрим по порядку, что мы здесь написали. Первое:
using var db = new ApplicationContext();
Класс ApplicationContext
через своего предка (базовый класс DbContext
) реализует интерфейс IDisposable
, поэтому для работы с ApplicationContext
мы можем использовать конструкцию using
. После того, как надобность в использовании класса отпадет, ресурсы, используемые классом, будут автоматически освобождены.
Далее мы, используя метод LINQ проверяем есть ли какая-либо информация в БД:
if (db.Users.Any() == false)
Если коллекция Users
будет пуста, то метод Any
вернет False
. Соответственно, если коллекция пуста, то далее мы создаем объект класса User
:
User user = new() { Name = "admin", Age = 30, Email = "admin@corp.gov" };
И далее, добавляем новый объект в коллекцию и сохраняем изменения:
db.Users.Add(user); db.SaveChanges();
После этого, мы получаем список пользователей из БД и выводим его в консоль:
List<User> users = db.Users.ToList(); foreach (User user in users) { Console.WriteLine($"{user.Id} {user.Name} {user.Email} {user.Age}"); }
При первом запуске приложения мы увидим следующую информацию в консоли:
Стоит обратить внимание на то, что при создании объекта мы не присваивали значение свойству Id
, однако, при записи объекта в БД это свойство было присвоено объекту автоматически.
Теперь мы можем снова вернуться в MySQL Workbench и посмотреть на содержимое нашей БД. Вот так выглядит теперь база данных:
Имя таблицы соответствует имени коллекции сущностей в контексте — в ApplicationContext
коллекция имеет названия Users
, а в БД создана таблица users
. Имена полей таблицы соответствуют именам свойств класса. В DDL наша таблица будет выглядеть следующим образом (всё это сделано EF Core):
CREATE TABLE `users` ( `Id` int NOT NULL AUTO_INCREMENT, `Name` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, `Email` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci, `Age` int NOT NULL, PRIMARY KEY (`Id`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
Итого
Таким образом, Entity Framework Core обеспечивает простое управление сущностями из базы данных, избавляя нас от непосредственной работы с конкретной базой данных — создание БД, таблиц в ней и прочие рутинные операции выполняются EF Core на основании классов модели и контекста данных.