Создание модели данных entity framework для приложения asp net mvc

Обновлено: 06.07.2024

Подавляющее большинство динамических сайтов для создания страниц на лету используют для заполнения контент, хранящийся в базе данных. Выбор и получение контента из таблиц базы данных происходит с высокой скоростью независимо от размера файла базы данных.

Модуль Entity Framework Core

Entity Framework Core – технология объектно-ориентированного доступа к данным. При работе с базами данных через модуль EF Core запрошенная таблица преобразуется в экземпляр класса, а столбцы в одноименные свойства. Изменения значений свойств сохраняется в базе данных.

При работе с Entity Framework Core классы модели базы данных сопоставляются таблицам базы. Инкапсуляция реляционных запросов превращает работу с базами данных в «обычное» объектно-ориентированное программирование. В отличие от этого драйверы реляционного доступа, возвращают данные в виде таблицы или параметров, которые требуют дополнительной обработки.

Установка необходимых пакетов NuGet

Для использования возможностей объектно-реляционного сопоставления «объект - база данных» необходима установка приложение пакета Microsoft.EntityFrameworkCore.

Кроме этого, понадобится установка расширений SqlServerDbContextOptionsExtensions. UseSqlServer для этого необходимо в веб приложение добавить пакет Microsoft.EntityFrameworkCore. SqlServer. Это необходимо для настройки контекста и создания строк подключения с помощью построителей.

База данных для исследования


Создадим базу данных MS SQL. Для этого необходим MS SQL Server или MS SQL Server Express и MS SQL Server Management Studio. Создавать таблицы и связи между ними будем посредством инструмента управления MS SQL Server Management Studio. Базу данных назовем DBMSSQL. Добавим в базу три небольшие таблицы кратко описывающие науки и ее разделы.

Между таблицами неразрывные отношения один-ко-многим (или многие-к-одному), и каждая запись может получить связанную с ней информацию из любой таблицы благодаря мостикам из внешних ключей.

  • PK (primary key) – первичный ключ
  • FK (foreign key) – ключ внешней связи
  • UI (unique index) – уникальный индекс

Модель базы данных

Модуль Entity Framework Core осуществляет доступ к базам данных посредством моделей. Модель – классы, определенные в соответствии таблицам базы данных. Entity Framework Core сопоставляет столбец таблицы и одноименное свойство класса соответствующей таблицы данных.

Соответственно таблицам создадим классы модели для базы данных DBMSSQL. Все таблицы в базе имеют одинаковые столбцы Id, Name, NumberViews, Uri. Чтобы уменьшить количество повторного программного кода создадим абстрактный класс с общими свойствами. Далее этот класс унаследуют классы модели базы данных.

Листинг модели базы данных:

Контекст сеанса с базой данных DBContext

Контекст баз данных представляется классом DBContext, необходимым для взаимодействия с базами данных. Объект класса производного от DBContext позволяет выполнять запросы и сохранять изменения, произведенные над свойствами экземпляров модели.

Во время взаимодействия с базой данных класс контекста наполняет классы модели информацией из таблиц базы данных. Сеанс взаимодействия контекста с базой данных краток, и состоит из одного цикла:

  • Создание объекта класса контекста
  • Получение данных (сохранение изменений)
  • Закрытие сеанса и удаление экземпляра контекста

Для наполнения классов модели информацией из базы в классе контекста необходимо определить свойства DbSet<TEntity>, где роль сущности (Entity) будут исполнять классы модели.

Класс DbSet<TEntity> - это оболочка для сущности (типа объекта таблицы базы данных), которой являются классы модели. Включение экземпляра класса DbSet<TEntity> в контекст означает, что он включен в модель Entity Framework Core. Свойства DbSet<TEntity> автоматически инициализируются при создании экземпляра класса контекста. Имена свойств, представляющих классы модели, должны быть идентичны названиям соответствующих таблиц в базе данных.

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

Листинг класса контекста для взаимодействия с базой данных DBMSSQL:

Строка подключения к SQL серверу

Реквизиты подключения к определенной базе данных, для контекста, указываются в строке подключения (connection string). Строку подключения к MS SQL Server удобно создавать с помощью построителей. Например, с помощью класса SqlConnectionStringBuilder, входящего в состав пространства имён Microsoft.Data.SqlClient (пакет Microsoft.EntityFrameworkCore.SqlServer). Таким способом создаётся синтактически правильная строка подключения к серверу базы данных.

Строка подключения отправляет серверу информацию для идентификации клиента, способе проверки клиента и выборе базы данных для последующих запросов. Разные режимы проверки подлинности пользователя требуют соответствующее содержание строки подключения.

Листинг двух вариантов строк подключения к SQL серверу:

Выполнение запросов к базе данных

Подключение к базе данных в веб приложении происходит при создании экземпляра класса контекста SqlDBContext. Экземпляр контекст создаётся в конструкторе контроллера HomeController.

После создания объекта контекста можно выполнять запросы к базе данных. В представления полученная информация передаётся в виде слабо-типизированных ViewBag и строго-типизированных объектов посредством Model.

Представление с моделью

Листинг представления с моделью:

Представление с ViewBag

Полученные данные можно передавать в представления динамическими переменными. Слаботипизированная переменная ViewBag может передавать любой объект, и что удобно, не требует приведения типов при присваивании соответствующему объекту.

В нашем случае в представление передаются списки объектов с информацией, полученной из базы данных. Путём перебора элементов списков, используя минимум кода Razor и разметки HTML, информация выводится в браузер в удобочитаемом виде.

Листинг представления с применением динамического свойства ViewBag:

    или Visual Web Developer Express 2010 SP1 (если вы используете для установки одну из этих ссылок, следующий софт установится автоматически)

The Contoso University

Приложение, которые вы разработаете, является простым вебсайтом университета.

clip_image001

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

clip_image002

clip_image003

clip_image004

UI близок по стилю к тому, что генерируется шаблонами по умолчанию, поэтому акцент будет на вопросах использования Entity Framework.

Подходы к разработке с Entity Framework

Исхоя из диаграммы, имеется три подхода к работе с данными в Entity Framework: Database First, Model First, и Code First.

clip_image005

Database First

В случае уже имеющейся базы данных Entity Framework может автоматически создать модель данных, состоящую из классов и свойств, соответствующих объектам базы даных (таким, как таблицы и столбцы). Информация о структуре базы (store schema), модель данных (conceptual model) и маппинг их друг на друга содержится в XML в файле .edmx. Visual Studio предоставляет графический дизайнер Entity Framework, с помощью которого можно просматривать и редактировать .edmx. Части Getting Started With the Entity Framework и Continuing With the Entity Framework в материалах о Web Forms используют подход Database First.

Model First

Если базы нет, вы можете начать с создания модели данных, используя дизайнер Entity Framework Visual Studio. После окончания работ над моделью дизайнер сгенерирует DDL (data definition language)-код для создания базы. В этом подходе для хранения информации о модели и маппингах также используется .edmx. What's New in the Entity Framework 4 включает небольшой пример разработки с использованием данного подхода.

Code First

Вне зависимости от наличия базы вы можете вручную написать код классов и свойств, соответствующих сущностям в базе и использовать этот код с Entity Framework без использования файла .edmx. Именно поэтому можно порой увидеть, как этот подход называют code only, хотя официальное наименование Code First. Маппинг между store schema и conceptual model в represented by your code is handled by convention and by a special mapping API. Если базы ещё нет, Entity Framework может создать, удалить или пересоздать её в случае изменений в модели.

API доступа к данным, разработанное для Code First, основано на классе DbContext . API может быть использован также и в процессе разработки с подходами Database First и Model First. Для дополнительной информации смотрите When is Code First not code first? В блоге команды разработки Entity Framework.

POCO (Plain Old CLR Objects)

По умолчанию для подходов Database First и Model First классы модели данных наследуются от EntityObject, который и предоставляет функциональность Entity Framework. Это значит, что эти классы не являются persistence ignorant и, таким образом, не полностью соответствуют одном из условий domain-driven design. Все подходы к разработке с Entity Framework также могут работать с POCO (plain old CLR objects), что, в целом, значит, что они являются persistence-ignorant из-за отсутствия наследования EntityObject .

Создание веб-приложения MVC

clip_image006

clip_image007

Настройка стилей

Несколько небольших поправок изменят меню сайта, расположение элементов и домашнюю страницу.

Для настройки меню Contoso University, в Views\Shared\_Layout.cshtml замените текст в h 1 и ссылки в меню, как в примере:


В Views\Home\Index.cshtml удалите всё в теге h2 .

В Controllers\HomeController.cs замените "Welcome to ASP.NET MVC!" на "Welcome to Contoso University!"

В Content\Site.css для смещения меню влево совершите следующие изменения:

clip_image001[1]

Создание модели данных

Далее создадим первые классы-сущности для Contoso University. Мы начнём со следующих трёх сущностей:

clip_image008

Установлена связь один-ко-многим между сущностями Student и Enrollment , и связь один-ко-многим между Course и Enrollment . Другими словами, студент может посещать любое количество курсов, и курс может иметь любое количество студентов, посещающих его.

В дальнейшем вы создадите классы для каждой из этих сущностей.

Note: компиляция проекта без созданных классов для этих сущностей вызовет ошибки компиляторов.

Сущность Student

clip_image009

В папке Models создайте Student.cs и замените сгенерированный код на:


Свойство StudentID будет первичным ключом соответствующей таблицы. По умолчанию, Entity Framework воспринимает свойство с ID или classname ID как первичный ключ.

Свойство Enrollments — navigation property. Navigation properties содержат другие сущности, относящиеся к текущей. В данном случае свойство Enrollments содержит в себе все сущности Enrollment , ассоциированные с текущей сущностью Student . Другими словами, если некая запись Student в базе данных имеет связь с двумя записями Enrollment (записей, содержащих значения первичных ключей для студента в поле внешнего ключа StudentID ), свойство этой записи Enrollments будет содержать две сущности Enrollment .

Navigation properties обычно помечаются модификатором virtual дабы использовать возможность Entity Framework, называемую lazy loading. (суть Lazy loading будет объяснена позже, в Reading Related Data) Если navigation property может содержать несколько сущностей (в связях многие-ко-многим и один-ко-многим), его тип должен быть ICollection .

Сущность Enrollment

clip_image010

В папке Models создайте Enrollment.cs со следующим содержанием:


Знак вопроса после указания типа decimal указывает на то, что свойство Grade nullable. Оценка, поставленная в null отличная от нулевой оценки— null обозначает то, что оценка еще не выставлена, тогда как 0 – уже значение.

Свойство StudentID является внешним ключом, и соответствующее navigation property Student . Сущность Enrollment ассоциирована с одной сущностью Student , поэтому свойство может содержать только одну сущность указанного типа (в отличие Student . Enrollments ).

Свойство CourseID является внешним ключом, и соответствующее navigation property Course . Сущность Enrollment ассоциирована с одной сущностью Course .

Сущность Course

clip_image011

В папке Models создайтеCourse.cs со следующим содержанием:


Свойство Enrollments — navigation property. Сущность Course может ассоциироваться с бесконечным множеством сущностей Enrollment .

Создание Database Context

Главный класс, координирующий функциональность Entity Framework для текущей модели данных называется database context. Данный класс наследуется от System . Data . Entity . DbContext . В коде вы определяете, какие сущности включить в модель данных, и также можете определять поведение самого Entity Framework. В нашем коде этот класс имеет название SchoolContext .

Создайте папку DAL и в ней новый класс SchoolContext.cs:


Код создаёт свойство DbSet для каждого множества сущностей. В терминологии Entity Framework множество сущностей (entity set) относится к таблице базы данных, и сущность относится к записи в таблице.

Содержимое метода OnModelCreating защищает имена таблиц от плюрализации, и, если вы этого не делаете, то получаете такие имена таблиц, как Students , Courses , Enrollments . В ином случае имена таблиц будут Student , Course , Enrollment . Разработчики спорят на тему того, нужно ли плюрализовывать имена таблиц или нет. Мы используем одиночную форму, но важен тот момент, что вы можете выбрать, включать эту строчку в код или нет.

(Этот класс находится в namespace Models потому, что в некоторых ситуациях подход Code First подразумевает нахождение классов сущностей и контекста в одном и том же namespace.)

Определение Connection String

Вам не нужно определять connection string. Если вы не определили эту строку, Entity Framework автоматически создаст базу данных SQL Server Express. Мы, однако, будем работать с SQL Server Compact, и вам необходимо будет создать строку подключения с указанием на это.

Откройте Web.config и добавьте новую строку подключения в коллекцию connectionStrings . (Убедитесь, что вы обновляете Web.config в корне проекта, так как есть еще один Web.config в папке Views, который трогать не надо.)


По умолчанию Entity Framework ищет строку подключения, названную также как object context class. Строка подключения, которую вы добавили, определяет базу данных School.sdf, находящуюся в папке App_data и SQL Server Compact.

Инициализация базы данных с тестовыми данными

Entity Framework может автоматически создать базу данных при запуске приложения. Вы можете указать, что это должно выплоняться при каждом запуске приложения или только тогда, когда модель рассинхронизирована с существующей базой. Вы можете также написать класс с методом, который Entity Framework будет автоматически вызывать перед созданием базы для использования её с тестовыми данными. Мы укажем, что база должна удаляться и пересоздаваться при изменении модели.

В папке DAL создайте новый класс SchoolInitializer.cs с кодом, с помощью которого база будет создана при необходимости и заполнена тестовыми данными.


Метод Seed принимает объект контекста базы как входящий параметр и использует его для добавления новых сущностей в базу. Для каждого типа сущности код создает коллекцию новых сущностей, добавляя их в соответствующее свойство DbSet, и потом сохраняет изменения в базу. Нет необходимости в вызове SaveChanges после каждой группы сущностей, как сделано у нас, но это помогает определить проблему в случае возникновения исключений.

Измените Global.asax.cs для того, чтобы наш код вызывался при каждом запуске приложения:

  • Добавьте using :
  • В методе Application_Start вызовите метод Entity Framework, который запускает код инициализации базы:

Note при развертывании приложения на продакшн-сервер вы должны удалить весь код, который инициализирует базу тестовыми данными.

Далее вы создадите веб-страницу для отображения данных, и процесс запроса данных автоматически инициирует создание базы. Вы начнете с нового контроллера, но перед этим, соберите проект для того, чтобы модель и контекстные классы стали доступны для MVC controller scaffolding.

Создание контроллера Student

Для создание контроллера Student , щелкните на папке Controllers в Solution Explorer, нажмите Add, Controller. В Add Controller совершите следующие действия и изменения и нажмите Add:

  • Controller name: StudentController.
  • Template: Controller with read/write actions and views, using Entity Framework. (по умолчанию.)
  • Model class: Student (ContosoUniversity.Models). (если этого нет, пересоберите проект)
  • Data context class: SchoolContext (ContosoUniversity.Models).
  • Views: Razor (CSHTML). (по умолчанию)

Откройте Controllers\StudentController.cs, вы увидите созданную переменную, инициализирующую объект контекста базы данных:


Действие Index собирает список студентов из свойства Students из экземпляра контекста базы данных:


Автоматическое scaffolding было создано для множества Student . Для настройки заголовков и последовательности колонок откройте Views\Student\Index.cshtml и замените код на:


Запустите сайт, нажмите на вкладку Students.

clip_image002[1]

Закройте браузер. В Solution Explorer выберите проект ContosoUniversity. Нажмите Show all Files, Refresh и затем разверните папку App_Data.

clip_image013

Два раза щелкните на School.sdf для открытия Server Explorer, и Tables.

Note если у вас возникает ошибка после того, как вы два раза щелкаете на School.sdf, убедитесь, что вы установили Visual Studio 2010 SP1 Tools for SQL Server Compact 4.0. Если все установлено, перезапустите Visual Studio.

clip_image014

Для каждой таблицы есть свое множество сущностей + одна дополнительная таблица. EdmMetadata используется для определения Entity Framework, когда случилась разсинхронизация модели и базы.

Щелкните на одной из таблиц и Show Table Data чтобы увидеть загруженные классом SchoolInitializer данные.

clip_image015

Закройте подключение, иначе может возникнуть проблема с запуском приложения.

clip_image016

Соглашения

Количество кода, нужное для создания Entity Framework базы, минимально из-за использования (conventions) Entity Framework. Некоторые из них уже были упомянуты:

  • Форма множественного числа имен классов сущностей используется в качестве имен таблиц.
  • Имена свойств сущностей используется в качестве имен столбцов.
  • Свойства сущностей с именами ID или classname ID распознаются как первичные ключи.
  • Entity Framework подключается к базе, отыскав строку подключения с таким же именем, как и класс контекста (в данном случае SchoolContext ).

Вы создали простое приложение с использованием Entity Framework и SQL Server Compact для хранения и отображения данных. Далее мы научимся совершать простые CRUD (create, read, update, delete) операции.

Подключение и создание базы данных в Entity Framework Core

Entity Framework Core в ASP.NET Core

Для взаимодействия с MS SQL Server через Entity Framework необходим пакет Microsoft.EntityFrameworkCore.SqlServer . По умолчанию он отсутствует в проекте, поэтому его надо добавить, например, через пакетный менеджер Nuget:

Entity Framework Core в ASP.NET Core

Далее добавим в проект класс модели, с которой мы будем работать. По умолчанию в проекте уже есть предназначенная для моделей папка Models. Определим в этой папке определим новый класс User:

Эта модель представляет те объекты, которые будут храниться в базе данных.

Чтобы взаимодействовать с базой данных через Entity Framework нам нужен контекст данных - класс, унаследованный от класса Microsoft.EntityFrameworkCore.DbContext . Поэтому добавим в папку Models новый класс, который назовем ApplicationContext (название класса контекста произвольное):

Свойство DbSet представляет собой коллекцию объектов, которая сопоставляется с определенной таблицей в базе данных. При этом по умолчанию название свойства должно соответствовать множественному числу названию модели в соответствии с правилами английского языка. То есть User - название класса модели представляет единственное число, а Users - множественное число.

Через параметр options в конструктор контекста данных будут передаваться настройки контекста.

В конструкторе с помощью вызова Database.EnsureCreated() по определению моделей будет создаваться база данных (если она отсутствует).

Чтобы подключаться к базе данных, нам надо задать параметры подключения. Для этого изменим файл appsettings.json , добавив в него определение строки подключения:

В данном случае мы будем использовать упрощенный движок базы данных LocalDB, который представляет легковесную версию SQL Server Express, предназначенную специально для разработки приложений.

И последним шагом в настройке проекта является изменение файла Startup.cs . В нем нам надо изменить метод ConfigureServices() :

Добавление контекста данных в виде сервиса позволит затем получать его в конструкторе контроллера через механизм внедрения зависимостей.

Во-первых, определим доменную модель, то есть что мы будем хранить в базе данных. Например, на нашем сайте пользователи смогут публиковать и редактировать статьи. Создадим подобный класс:

Во-вторых, нам понадобится так называемый контекст базы данных. Это специальный класс, который координирует работу Entity Framework между базой данных и доменной моделью нашего приложения.

В описанном выше классе важно следующее:

Далее переключаемся в класс Startup.cs, в метод ConfigureServices(). В этом месте непосредственно указывается вся конфигурация для нашего приложения, например, переадресация, кэш, сессия, маршрутизация и т.д. Нас в данном примере интересует настройки для контекста базы данных.

В коде выше мы регистрируем наш контекст и через опции указываем, что он будет подключаться к базе данных на сервере MS SQL. Далее в опциях сервера мы определяем строку подключения к базе данных. В данном примере строка подключения означает следующее:

  • источник данных - локальный SQL-сервер.
  • название базы данных - Articles.
  • Persist Security Info=False - запрещаем получение важных данных из строки подключения после открытия соединения.
  • MultipleActiveResultSets=True - также разрешаем возможность выполнения нескольких пакетов по одному соединению (MARS).
  • Trusted_Connection=True - даем возможность при соединении использовать режим Windows-аутентификации.

* в вашем проекте строка подключения конечно же может отличаться.

К данному моменту мы определили доменную модель, создали пользовательский контекст базы данных, и также настроили его для работы. Все готово для создания первой миграции. Для работы с миграциями и вообще Entity Framework можно использовать либо командное окно в Visual Studio Package Manager Console, либо стандартный PowerShell. В данном примере воспользуемся первым вариантом.

Как найти окно Package Manager Console

Добавим новую первую миграцию с помощью команды:
add-migration _initial

После создания первой миграции в проекте появится папка Migrations

После создания первой миграции в проекте появится папка Migrations

Далее применим созданную миграцию и обновим базу данных. В нашем примере база данных еще не существует, и она будет создана. Применяем команду в Package Manager Console:
update-database

На данном этапе связь между веб-приложением и сервером баз данных установлена. Чтобы было удобнее работать со статьями и совершать над ними стандартные CRUD-операции (create, read, update, delete), создадим класс-репозиторий.

Благодаря классу-репозиторию мы скрываем детали работы контекста базы данных. Теперь все манипуляции со статьями будут проходить только через репозиторий. Также зарегистрируем репозиторий как сервис в классе Startup.cs в методе ConfigureServices(), чтобы была возможность использовать его в других классах.

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

Последнее что остается - это создать соответствующие представления. Далее представлена простейшая HTML-разметка.


Взаимосвязи EF Core - концепции и свойства навигации

В настоящее время у нас есть только один класс сущности (модели), класс Student , но довольно скоро мы собираемся создать остальную часть модели базы данных в нашем приложении. Но прежде чем мы это сделаем, очень важно понять некоторые основные концепции при работе с реляционными базами данных и моделями.

Когда мы создаем связь между двумя объектами, одна из них становится основной сущностью, а другая - зависимой сущностью. Основная сущность - это основная сущность во взаимоотношениях. Он содержит первичный ключ как свойство, на которое зависимая сущность ссылается через внешний ключ. Зависимая сущность, с другой стороны, - это сущность, которая содержит внешний ключ, который относится к первичному ключу основной сущности.

Наши классы сущностей будут содержать навигационные свойства, которые представляют собой свойства, содержащие один класс или набор классов, которые EF Core использует для связывания классов сущностей.

Кроме того, давайте объясним отношения Required и Optional в EF Core. Обязательная связь - это связь, в которой внешний ключ не может быть нулевым. Это означает, что должен существовать главный объект. Необязательное отношение - это отношение, в котором внешний ключ может иметь значение NULL и, следовательно, основной объект может отсутствовать.

Настройка One-to-One связи

Отношение "один к одному" означает, что строка в одной таблице может относиться только к одной строке в другой таблице в связи. Это не такая распространенная связь, потому что она обычно обрабатывается как «все данные в одной таблице», но иногда (когда мы хотим разделить наши сущности) полезно разделить данные на две таблицы.

Самый простой способ настроить этот тип отношений - использовать подход по соглашению, и это именно то, что мы собираемся сделать. Итак, давайте сначала создадим еще один класс в проекте Entities с именем StudentDetails :

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

И давайте изменим класс StudentDetails :

Мы можем видеть, что класс Student имеет свойство навигации по ссылке к классу StudentDetails , а класс StudentDetails имеет внешний ключ и свойство навигации Student .

В результате мы можем создать новую миграцию и применить ее:

Настройка One-to-One связи EF Core

Отлично, отлично работает.

Дополнительные пояснения

Как мы объяснили в первой статье, EF Core ищет все общедоступные свойства DbSet<T> в классе DbContext для создания таблиц в базе данных. Затем он ищет все общедоступные свойства в классе T для сопоставления столбцов. Но он также выполняет поиск всех общедоступных свойств навигации в классе T и создает дополнительные таблицы и столбцы, связанные с типом свойства навигации. Итак, в нашем примере в классе Student EF Core находит свойство навигации StudentDetails и создает дополнительную таблицу со своими столбцами.

Конфигурация отношений One-to-Many

В этом разделе мы узнаем, как создавать отношения "один ко многим" всеми тремя способами. Итак, прежде чем мы начнем, давайте создадим дополнительный класс модели Evaluation в проекте Entities :

Использование условного подхода для создания отношений «один ко многим»

Давайте посмотрим на различные соглашения, которые автоматически настраивают связь "один ко многим" между классами Student и Evaluation .

Первый подход включает свойство навигации в основной сущности, классе Student :

В классе ApplicationContext есть свойство DbSet , и, как мы объяснили, EF Core выполняет поиск по классу Student , чтобы найти все свойства навигации для создания соответствующих таблиц в базе данных.

Еще один способ создать связь "один ко многим" - это добавить свойство Student в класс Evaluation без свойства ICollection в классе Student класс :

Чтобы этот подход работал, мы должны добавить свойство DbSet<Evaluation> Evaluations в класс ApplicationContext .

Третий подход по Конвенции заключается в использовании комбинации предыдущих. Итак, мы можем добавить свойство навигации ICollection<Evaluation> Evaluations в класс Student и добавить свойство навигации Student Student в класс Evaluation . Конечно, при таком подходе нам не нужно свойство DbSet<Evaluation> Evaluations в классе ApplicationContext .

Это результат любого из этих трех подходов:

Настройка связей сущностей в EF Core

Мы видим, что связь была создана правильно, но наш внешний ключ является полем, допускающим значение NULL. Это связано с тем, что оба свойства навигации имеют значение по умолчанию null. Это отношение также называется необязательным отношением (мы говорили об этом в первой части этой статьи).

Если мы хотим создать требуемую связь между сущностями Student и Evaluation , мы должны включить внешний ключ в класс Evaluation . :

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

Миграции EF Core

Очевидно, что наши отношения сейчас необходимы.

Подход с аннотациями данных

Подход с использованием аннотаций к данным содержит только два атрибута, связанных с отношениями. Атрибуты [ForeignKey] и [InverseProperty] .

Атрибут [ForeignKey] позволяет нам определять внешний ключ для свойства навигации в классе модели. Итак, давайте изменим класс Evaluation , добавив этот атрибут:

Мы применили атрибут [ForeignKey] поверх свойства StudentId (которое является внешним ключом в этом классе), присвоив ему имя свойства навигации Student . Но работает и наоборот:

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

[ForeignKey («Свойство1», «Свойство2»)] .

Какой бы способ мы ни выбрали, результат будет таким же, как и при подходе «по соглашению». Мы собираемся создать требуемую связь между этими двумя таблицами:

Установление связей меду таблицами в EF Core

Подход Fluent API для конфигурации One-to-Many

Чтобы создать отношение «один ко многим» с этим подходом, нам нужно удалить атрибут [ForeignKey] из класса Evaluation и изменить StudentConfiguration , добавив этот код:

С помощью такого кода мы сообщаем EF Core, что наша сущность Student (объект построителя имеет тип) могут быть связаны со многими объектами Evaluation . Мы также заявляем, что Evaluation находится во взаимосвязи только с одной сущностью Student . Наконец, мы предоставляем информацию о внешнем ключе в этой связи.

Результат будет таким же:

One-to-Many связь в EF Core

Здесь нужно упомянуть одну вещь.

Для модели базы данных, такой как мы определили, нам не нужен метод HasForeignKey . Это потому, что свойство внешнего ключа в классе Evaluation имеет тот же тип и то же имя, что и первичный ключ в классе Student. Это означает, что по Конвенции это отношение все равно будет обязательным. Но если бы у нас был внешний ключ с другим именем, например StudId, тогда понадобился бы метод HasForeignKey , потому что в противном случае ядро EF создало бы необязательную связь между классами Evaluation и Student.

Конфигурация отношений Many-to-Many (многие-ко-многим)

Это реализация версии 3.1 EF Core. Это справедливо для EF Core версии 5, но в версии 5 это можно было бы сделать немного иначе. Мы объясним это в следующем разделе.

Прежде чем мы начнем объяснять, как настроить эту связь, давайте создадим необходимые классы в проекте Entities :

Теперь мы можем изменить классы Student и Subject , предоставив свойство навигации для каждого класса по направлению к классу StudentSubject :

В Entity Framework Core мы должны создать объединяющуюся сущность для объединяемой таблицы (StudentSubject). Этот класс содержит внешние ключи и свойства навигации из классов Student и Subject . Кроме того, классы Student и Subject имеют свойства навигации ICollection по отношению к классу StudentSubject . Таким образом, отношения «многие ко многим» - это всего лишь два отношения «один ко многим».

Мы создали наши сущности, и теперь нам нужно создать необходимую конфигурацию. Для этого давайте создадим класс StudentSubjectConfiguration в папке Entities/Configuration:

Как мы уже говорили, многие-ко-многим - это всего лишь две взаимосвязи EF Core «один ко многим», и это именно то, что мы настраиваем в нашем коде. Мы создаем первичный ключ для таблицы StudentSubject , который в данном случае является составным ключом. После настройки первичного ключа мы используем знакомый код для создания конфигураций отношений.

Теперь нам нужно изменить метод OnModelBuilder в классе ApplicationContext :

После этих изменений мы можем создать миграцию и применить ее:

PM> Add-Migration ManyToManyRelationship

Связь Many-to-Many в EF Core

Отличная работа. Давай продолжаем.

По сути, класс Student должен иметь public ICollection Subjects , а класс Subject должен иметь public ICollection Students свойство. Нет необходимости ни в третьем классе, ни в свойствах навигации для этого класса.

Но если вы хотите изначально заполнить данные для таблиц Student и Subject и заполнить третью таблицу идентификаторами обоих таблиц, вам придется использовать реализацию, которую мы использовали для версии 3.1.

Метод OnDelete

Метод OnDelete настраивает действия удаления между реляционными сущностями. Мы можем добавить этот метод в конец конфигурации отношений, чтобы решить, как будут выполняться действия удаления.

В методе OnDelete можно использовать следующие значения:

  • Restrict - действие удаления не применяется к зависимым объектам. Это означает, что мы не можем удалить основную сущность, если у нее есть связанная зависимая сущность.
  • SetNull - зависимая сущность не удаляется, но для ее свойства внешнего ключа установлено значение null.
  • ClientSetNull - если EF Core отслеживает зависимую сущность, ее внешний ключ имеет значение null, и эта сущность не удаляется. Если он не отслеживает зависимую сущность, то применяются правила базы данных.
  • Cascade - зависимая сущность удаляется вместе с основной сущностью.

Мы также можем видеть это из кода в нашем файле миграции:

onDelete в миграциях EF Core

Мы можем изменить этот тип поведения, изменив код конфигурации в классе StudentConfiguration :

Давайте создадим еще один перенос:

PM> Добавление миграции StudentEvaluationRestrictDelete

И взгляните на сгенерированный код миграции:

Миграции FluentApi с onDelete в EF Core

Заключение

Настройка взаимосвязей EF Core в нашей модели базы данных - очень важная часть процесса моделирования.

Мы увидели, что EF Core предлагает нам несколько способов добиться этого и максимально упростить процесс.

Теперь, когда мы знаем, как устанавливать отношения в нашей базе данных, мы можем перейти к следующей статье, где узнаем, как получить доступ к данным из БД.

Читайте также: