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

Обновлено: 06.07.2024

В основе Entity Framework лежит сущностная модель данных (EDM). В модели EDM определяются типы сущностей, отношения и контейнеры, а разработчик взаимодействует со всем этим посредством кода. Платформа Entity Framework строит соответствия между упомянутыми элементами и схемой хранения, которую предоставляет реляционная база данных. Модель EDM платформа Entity Framework использует через XML, в котором определяется концептуальная модель приложения. Определяться она может как самостоятельно, так и вместе с кодом XML, определяющим схему хранилищ, и с кодом XML, определяющим соответствия между ними. Код XML можно (а иногда и нужно) изменять вручную, однако гораздо проще корректировать сущностную модель и сопоставления в новом визуальном средстве разработки сущностных моделей данных.

В этом месяце мы расскажем о том, как разработать сущностную модель данных в новом средстве проектирования EDM и как изменять код XML, определяющий и модель, и сопоставления. Начнем мы с описания модулей, взаимодействующих внутри платформы Entity Framework (в том числе LINQ), а затем коснемся возможностей применения EDM. Кроме этого, мы продемонстрируем этапы создания сущностной модели и сопоставлений в визуальном конструкторе. И наконец, мы рассмотрим несколько окон, которые используются при исследовании и корректировке модели и сопоставлений.

В этой статье мы попытаеся разъяснить роли различных компонентов модели EDM, таких как EntityType и Association. Примеры, которые мы рассмотрим, иллюстрируют создание базовых сущностей. Обратите внимание, что во всех примерах используется Visual Studio® 2008 и соответствующая бета-версия 3 платформы Entity Framework (они устанавливаются отдельно). База данных, которую мы будем использовать, — это пересмотренная база данных Northwind. Она прилагается к бета-версии 3.

Что такое EDM

Прежде чем углубляться в создание и управление сущностной моделью, расскажем вкратце, что же такое модель EDM и как она взаимодействует с остальными составляющими платформы Entity Framework. Платформа Entity Framework состоит из множества компонентов. К ним, в частности, относится спецификация EDM и связанные с ней сопоставления, интерфейсы API, взаимодействующие с моделью EDM, и средства, помогающие при определении и управлении сущностной моделью и сопоставлениями. После создания сущностной модели можно писать на ее основе код, используя различные интерфейсы API, например поставщик EntityClient или службы объектов (в том числе LINQ to Entities).

Рис. 1 Обзор Entity Framework

Такие методы доступа к данным дают возможность взаимодействовать с концептуальными сущностями, определенными в сущностной модели, а не с объектами физического хранилища (к примеру реляционной базы данных). Модель данных и связанные с ней сопоставления создаются либо при помощи визуального конструктора, либо вручную, — путем изменения кода XML, содержащего определения. Платформа Entity Framework, показанная на рис. 2, обеспечивает связь между приложением и базой данных. EDM используется для описания бизнес-сущностей через концептуальную сущностную модель, а платформа Entity Framework (посредством настройки сопоставлений) переводит их в физическую форму, то есть в таблицы, представления, функции и процедуры базы данных.

Рис. 2 Entity Framework подключает приложение к своей базы данных

Сущностная модель приложения описывается на языке CSDL. CSDL — это язык формата XML, в котором определяются сущности и связи между ними. Разработчик взаимодействует с ними через интерфейс API, например LINQ to Entities. В платформе используется также язык SSDL — язык формата XML, используемый для определения схем хранилищ реляционных баз данных, — и язык MSL, используемый для задания соответствий между сущностями CSDL и схемой хранилищ, описанной на языке SSDL.

В CSDL разработчик имеет наибольшую свободу действий, поскольку именно здесь определяются сущности, с которыми ему чаще всего и приходится работать. На рис. 2 показано, что одни сущности могут сопоставляться отдельным таблицам в базе данных, а другие — целой группе таблиц. Сопоставление сущностей формируется группой разработчиков на основе бизнес-модели. Она зачастую строится вокруг одной единственной сущности, которая представляется несколькими физическими таблицами базы данных. На рис. 2 также показано, что сущность может сопоставляться представлению базы данных и может принимать метод, вызывающие хранимые процедуры. Сущности могут выводиться из других сущностей с использованием схемы наследования, существующей в концептуальной модели. Это лишь несколько способов формирования сущностной модели, доступных в средствах проектирования EDM.

Построение EDM при помощи мастера

Создание сущностной модели начинается с добавления в проект ADO. NET нового файла EDM (см. <Fig>рис. 3</Fig>). После этого мастер EDM предложит либо создать модель на основе базы данных, либо начать с пустой модели. Создать модель на основе базы данных — неплохое решение, если доступ к базе данных у вас уже есть. Некоторые методики разработки, к примеру проектирование на основе областей, предполагают создание сущностной модели области до проектирования базы. В таком случае удобнее начать с пустой модели, а затем наполнить ее сущностями в визуальном конструкторе EDM. В качестве примера мы построили сущностную модель на основе базы данных Northwind.

Рис. 3 Добавление EDM-файла к проекту

В следующем окне мастер просит ввести информацию, необходимую для подключения к базе данных. Затем предлагается указать, какие объекты базы данных нужно включить в модель. Как видно из рис. 4, мы переносим в модель все таблицы и все хранимые процедуры базы данных Northwind, за исключением тех, которые используются для построения диаграмм. Таблицы изначально напрямую сопоставляются с сущностями, а хранимые процедуры можно сопоставить методам созданного контейнера.

Рис. 4 Выбор объектов базы данных

После выбора объектов, включаемых в модель, мастер EDM создает файл EDMX, в котором определяется модель и сопоставления, и добавляет в проект ссылки в соответствии с требованиями платформы Entity Framework. Файл EDMX — это файл формата XML, состоящий из четырех основных разделов: сведений о визуальном представлении концептуальной модели в программе-конструкторе, описания концептуальной модели на языке CSDL, описания слоя сопоставлений на языке MSL о писания физической модели на языке SSDL. Вся эта информация записывается в один файл.

Данные, хранящиеся в файле EDMX, используются в Visual Studio для создания послойного представления модели в программе-конструкторе. Делается это только в процессе проектирования. Коды CSDL, MSL и SSDL используются в момент компиляции для создания классов, которыми будет представлена модель EDM.

Хранимые процедуры в сущностной модели

Во время создания модели мы добавили в нее хранимые процедуры, однако включены они были только в определение SSDL. Хранимые процедуры могут взаимодействовать с самыми различными таблицами, а также с другими объектами базы данных, поэтому платформа Entity Framework не берется автоматически сопоставить хранимую процедуру какой-то конкретной сущности в определении CSDL. Для создания метода, порождающего сопоставления для хранимой процедуры, нужно отредактировать код XML в файле EDMX.

Чтобы создать метод, который будет возвращать сущности данного типа, нам сначала нужно выбрать хранимую процедуру. В качестве примера мы добавим метод GetTenMostExpensiveProducts. Он будет вызывать хранимую процедуру Ten Most Expensive Products и возвращать объекты типа Product. Поскольку в коде SSDL хранимая процедура уже определена как элемент Function, нам нужно сделать следующий шаг — добавить метод в код CSDL. Для этого нужно добавить элемент FunctionImport в EntityContainer в качестве дочернего элемента:

В атрибуте Name указывается имя метода для сущностного контейнера. В атрибуте EntitySet указывается набор EntitySet. Атрибут ReturnType ссылается на тип возвращаемых сущностей EntityType (или коллекцию значение EntityTypes, как в нашем случае).

Ссылка на Self в данном примере — это псевдоним, указывающий на текущее пространство имен, то есть на NWModel. Обратите внимание, что здесь можно было поставить как Self, так и NWModel.

Если для работы метода требуются параметры, их можно добавить при помощи тега <Parameter>. Например, если бы в хранимой процедуре был параметр CategoryId и мы бы решили его включить в метод, мы бы добавили в элемент FunctionImport следующий фрагмент кода XML:

Но в нашем примере параметры не используются, поэтому мы просто пропустим этот шаг.

Итак, в коде CSDL определен метод, тип сущностей, который он возвращает, и набор EntitySet, к которому должны принадлежать возвращаемые сущности, а в коде SSDL определена хранимая процедура. Теперь необходимо построить сопоставление между CSDL и SSDL, чтобы концептуальный метод знал, какую хранимую процедуру он должна выполнять. Сопоставление выполняется путем добавления следующего фрагмента кода (FunctionImportMapping) в раздел EntityContainerMapping в определении MSL:

Здесь элемент FunctionImportMapping использует атрибут FunctionName — с его помощью он ссылается на полное имя элемента Function, определенного в SSDL. Элемент FunctionImportName ссылается на имя элемента FunctionImport, определенного в CSDL.

Окна, используемые при работе с EDM

После того, как модель EDM спроектирована и построена, можно контролировать ее состояние при помощи различных окон. Окно «Представление классов» (см. рис. 5), которое существовало и раньше, помогает определить, какие объекты имеются в распоряжении разработчика. Например, в нем будет отображаться созданный нами метод GetTenMostExpensiveProducts для класса EntityContainer в модели NWEntities, а также все классы, имеющиеся в пространстве имен NWModel. В этот список входит по одному классу на каждый тип EntityType в коде CSDL плюс один класс для всей модели NWEntities.

Рис. 5 EDM в представлении классов

В платформе также появилось несколько новых окон, предоставляющих сведения о сущностной модели и связанных с ней сопоставлениях. К ним относится конструктор EDM, окно сведений о сопоставлениях сущностей и окно просмотра сущностной модели.

В окне просмотра сущностной модели содержатся все компоненты CSDL и SSDL, в том числе EntityTypes, Associations, EntitySets, AssociationsSets и Function Imports (компоненты CSDL), а также все элементы SSDL.

В конструкторе EDM (см. рис. 6) показывается схема модели, созданной разработчиком. Здесь все элементы концептуальной модели представлены наглядным образом. Разработчик может просматривать модель и управлять ею. Обратите внимание на сущность Product, показанную на рис. 6 — она соответствует типу Product EntityType в CSDL. Каждый тип EntityType имеет список свойств — как скалярных, так и навигационных.

Рис. 6 Конструктор сущностной модели данных

Навигационные свойства используются при переходе по связям CSDL. Навигационные свойства становятся общими свойствами соответствующего класса EntityType и используются для ссылки на другую сущность или набор сущностей, связанный с исходной сущностью. Допустим, тип EntityType Product имеет навигационное свойство Categories, которое ссылается на сущность Category, относящуюся к конкретному экземпляру сущности Product. Тип EntityType Category, в свою очередь, имеет навигационное свойство Products. Существует оно для того, чтобы любой экземпляр сущности Category можно было связать с сущностями Product.

Тут можно сделать немаловажный вывод о том, что основным элементам, таким как EntityType, EntityContainer и Association, имена лучше давать до изменения модели данных. Это сведет к минимуму число изменений, которые нужно будет вносить в код вручную. Это касается также того кода, который уже когда-то создавался на основании изменяемой модели данных. В случае возникновения проблем окно «Список ошибок» скорее всего должно помочь, постому что в нем наверняка будут содержаться указания на те элементы, для которых имеются неверные ссылки в коде XML.

И наконец, окно свойств сопоставлений сущностей (в отличие от конструктора, показывающего концептуальную модель) дает возможность просмотреть и изменить сопоставления (код MSL) между EDM и хранилищем данных.

Производные сущности

Те же средства, что помогают при проектировании сущностной модели, позволяют ее изменять. В объектно-ориентированном программировании понятие наследования является одним из основных. Модель EDM поддерживает создание и изменение производных сущностей — как непосредственно в коде XML, так и в наглядной форме в конструкторе EDM.

Чтобы проиллюстрировать процесс разработки производных сущностей, мы создадим тип EntityType DiscontinuedProduct на основе типа EntityType Product. Тип EntityType Product имеет скалярное свойство Discontinued, принимающее значения логического типа. Его мы используем в качестве условия, определяющего принадлежность каждого отдельно взятого продукта к тому или иному типу экземпляров. В конструкторе EDM мы щелкаем правой кнопкой мыши и во всплывшем меню выбираем пункт «Добавить» > «Сущность». Затем мы вводи имя новой сущности — DiscontinuedProduct — и выбираем сущность Product в качестве базовой (см. рис. 7).

Рис. 7 Создание унаследованной сущности

На следующем этапе нам нужно определить фактор различения этих сущностей, что делается при помощи условия. Мы выбираем в конструкторе тип EntityType Product и открываем окно свойств сопоставления сущностей. В столбце сопоставлений мы выбираем свойство Discontinued и удаляем сопоставление. При этом свойство Discontinued удаляется как из типа Product, так и из типа DiscontinuedProduct (выражение, участвующее в создании условия, не должно использоваться в качестве свойства). Затем мы переходим к разделу Maps to Products в окне свойств сопоставления сущностей и добавляем условие Condition of Discontinued = 0. После этого выбираем тип DiscontinuedProduct и добавляем условие Condition of Discontinued = 1.

Условия создаются в разделе EntityTypeMapping в коде MSL. Они фактически просто устанавливают фильтр на получение строк. При сохранении данных условия используются для того, чтобы определить, какое значение записать в столбец базы данных, основанный на производном типе.

Выводы

Средства конструирования, включенные в Visual Studio 2008, и файлы XML позволяют создать сущностную модель данных, в которой будет использоваться наследование и применяться хранимые процедуры, — модель, позволяющую сосредоточиться на бизнес-процессах, вместо того чтобы писать код непосредственно на основании схемы реляционной базы данных. После того как сущностная модель полностью оформлена, взаимодействие с ней через интерфейсы API, такие как службы объектов, проблем не вызывает. Кроме того, при изменении модели данных вам не придется вносить изменения в базу данных, поскольку сопоставления позволяют обособить концептуальную модель от модели хранилищ.

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

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

С помощью Entity Framework Designer: разработчик рисует поля и строки для указания модели с помощью Entity Framework Designer. Результирующая модель хранится в виде XML-файла с расширением EDMX. Объекты предметной области приложения обычно создаются автоматически на основе концептуальной модели.

Рабочие процессы EF

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

Мне нужно просто написать код… Я хочу использовать конструктор.
Я создаю базу данных Используйте Code First для определения модели в коде, а затем создайте базу данных. Используйте Model First для определения модели с помощью полей и строк, а затем создайте базу данных.
Мне требуется доступ к существующей базе данных Используйте Code First для создания модели на основе кода, которая сопоставляется с существующей базой данных. Используйте Database First для создания модели полей и строк, которая сопоставляется с существующей базой данных.

Просмотрите видео о выборе подходящего рабочего процесса EF.

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

Бегунок выбора рабочего процесса

WMV MP4 WMV (ZIP)

Если после просмотра видеоролика вы все еще не можете решить, что будете использовать — Entity Framework Designer или Code First, — изучите оба подхода.

Взгляд изнутри

Независимо от того, используете ли вы Code First или Entity Framework Designer, модель EF всегда состоит из нескольких компонентов.

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

Концептуальная модель, состоящая из соответствующих предметной области типов сущностей и связей, описываемых с помощью модели EDM. Этот уровень часто указывается с буквой C, означающей conceptual (концептуальный).

Модель хранения, представляющая таблицы, столбцы и связи, как определено в базе данных. Этот уровень часто указывается с буквой S, означающей S (хранение).

Сопоставление концептуальной модели со схемой базы данных. Это сопоставление, часто называют сопоставлением C-S.

Подсистема сопоставления EF использует сопоставление C-S для преобразования операций с сущностями (создание, чтение, обновление и удаление) в эквивалентные операции для таблиц в базе данных.


Сущности (модели) - классы, отображаемые в базе данных

Добавление нового проекта ASP.NET Core Web application

Нам необходимо установить библиотеки Microsoft.EntityFrameworkCoreи Microsoft.EntityFrameworkCore.SqlServer . Это можно сделать с помощью диспетчера NuGet или окна консоли диспетчера пакетов.

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

Давайте создадим папку Entities и внутри класса с именем Student :

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

Затем все общедоступные свойства этого класса будут сопоставлены с одноименными столбцами таблицы. Наконец, EF Core использует соглашение об именах для создания первичного ключа из свойства StudentId в таблице базы данных (позже, в разделе «Настройка нереляционных свойств», мы увидим, как это сделать).

Создание класса модели или классов модели - лишь одна часть головоломки. Чтобы в EF Core была необходимая информация о базе данных для работы, нам необходимо предоставить строку подключения, изменив файл appsettings.json .

Размещение строки подключения в файле appsettings.json - обычная практика (и мы собираемся использовать ту же практику в этой статье), потому что мы можем использовать разные файлы настроек приложения для разных сред:

  • Development.json - содержит настройки, относящиеся к среде разработки.
  • Production.json - содержит настройки, относящиеся к производственной среде.
  • appsettings.json - содержит настройки, общие для обеих сред.

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

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

Вот и все, мы можем перейти к классу контекста.

Класс контекста - еще одна важная часть приложения. Этот класс должен наследовать от базового класса DbContext , который содержит информацию и конфигурацию для доступа к базе данных. Итак, давайте создадим наш контекстный класс с именем ApplicationContext в папке Entities :

Дополнительные параметры отправляются в базовый класс DbContext через конструктор ApplicationContext с помощью параметра DbContextOptions . Наконец, мы видим свойство Student типа DbSet<Student> , и это довольно важная часть.

EF Core ищет все общедоступные свойства DbSet внутри класса контекста приложения, а затем сопоставляет их имена с именами таблиц в базе данных. Затем он входит в класс, который предоставляется в свойстве `DbSet ` (в нашем случае это класс Student ), и сопоставляет все общедоступные свойства в столбцы таблицы с одинаковыми именами и типами (StudentId, Name и Age).

Если наш класс Student имеет какие-либо ссылки на другие классы (прямо сейчас их нет, но мы создадим отношения в следующих статьях), EF Core будет использовать эти ссылочные свойства и создавать отношения в база данных.

После того, как мы закончили создание класса ApplicationContext , мы можем перейти к его регистрации.

Для этого мы собираемся открыть класс Startup.cs и изменить метод ConfigureServices :

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

О AddDbContextPool

Вместо метода AddDbContext мы можем использовать метод AddDbContextPool. Мы можем использовать либо первый, либо второй метод, но во втором методе мы включаем пул DbContext. Это не будет создавать каждый раз новый экземпляр, но сначала проверит, есть ли доступные экземпляры в пуле, и если они есть, он будет использовать один из них.

Сейчас наш класс контекста готов к использованию с инъекцией зависимостей (DI) внутри нашего приложения. Итак, давайте добавим контроллер Values ​​(API) и изменим его:

Как вы могли заметить, мы внедряем наш класс контекста внутрь конструктора контроллера, что является обычным решением для DI.

Углубляемся в класс DbContext

Наш класс ApplicationContext в настоящее время принимает один параметр типа DbContextOptions внутри конструктора. Но мы также можем предоставить общую версию параметра DbContextOptions :

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

Если мы перейдем к определению DbContext, мы увидим, что внутри у него есть три свойства:

  • База данных - это свойство отвечает за транзакции, перенос / создание базы данных и необработанные SQL-запросы (обо всем этом мы поговорим в следующих статьях).
  • ChangeTracker - это свойство используется для отслеживания состояний объектов, полученных с помощью одного и того же экземпляра контекста (это также будет рассмотрено в следующих статьях).
  • Модель - это свойство обеспечивает доступ к модели базы данных, которую EF Core использует при подключении или создании базы данных.

Мы можем использовать свойство Model для доступа к информации о каждой сущности и ее свойствах.

После установки мы можем изменить наше действие Get:

Это всего лишь несколько примеров использования свойства Model , но, тем не менее, этого должно быть достаточно, чтобы понять зачем оно нужно.

Entity Framework Model First

Model First в EF

Выбираем "Пустая модель конструктора EF":

Model First в EF

Далее мы увидим, что создалась пустая модель:

Model First в EF

Добавим в дизайнер несколько сущностей. Делается это в панели элементов:

Model First в EF

Можно перетащить на дизайнер, либо 2 раза щёлкнуть мышью. После добавления у нас появится одна сущность. Добавим нашей сущности несколько свойств. По умолчанию все свойства создаются типа string. Тип свойства можно изменить, щёлкнув правой кнопкой по мыши и выбрав пункт меню "Свойства". Как у нас теперь выглядит сущность:

Model First в EF

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

Model First в EF

Model First в EF

При нажатии "Готово" будет сгенерирован скрипт, который необходимо будет выполнить ("Ctrl + Shift + E"):

Model First в EF

Сохраним нашу модель.

Видим, что сгенерировался класс нашей сущности и класс контекста:

Model First в EF

База данных также успешно создалась:

Model First в EF

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

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

На связи был Алексей Гулынин, оставляйте свои комментарии, увидимся в следующих статьях.

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