Развитие Entity Framework

65

При работе с реляционными базами данных мы используем таблицы со строками и столбцами, такая инфраструктура устройства баз данных является очень структурированной. Перед широким внедрением объектно-ориентированного программирования мы работали в рамках “процедурного” программирования – для решения проблем использовался структурный код и функции. Устройство баз данных в виде таблиц, строк и столбцов было в какой-то степени похоже на структурные и процедурные шаблоны программирования, которые мы использовали в нашем коде. Жизнь была хороша ...

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

При этом эти изменения практически не затронули базы данных. Данные все также остаются заперты в таблицах, строках и столбцах. Это создает большую пропасть в работе между иерархическим объектно-ориентированным кодом и высоко-нормализованной структурой баз данных. Чтобы справиться с этой проблемой, разработчики предложили внести в программные проекты “объектный слой базы данных”, в котором таблицы баз данных представлялись в виде классов, столбцы в виде свойств, а вся работа с базой данных строилась на программном коде без использования SQL. Такой подход получил название объектно-реляционного отображения (object-relational mapping — ORM).

Различные программные платформы предлагают множество систем, реализующих модель ORM. Entity Framework в сочетании с LINQ (Language-Integrated Query) представляет собой реализацию ORM для платформы .NET Framework от компании Microsoft. Entity Framework содержит механизмы создания и работы с сущностями базы данных через объектно-ориентированный код на языке, совместимым с CLR (в наших примерах мы будем использовать C#). LINQ представляет собой библиотеку, расширяющую возможности C#, и облегчающую создание запросов (благодаря LINQ можно создавать SQL-подобные запросы в коде C#).

Entity Framework является продолжением другого API-интерфейса для работы с базами данных в .NET – ADO.NET, в котором для работы с базами данных приходилось писать запросы на SQL и вставлять их в команды. Думаю как вы поняли, Entity Framework значительно облегчает жизнь программистам C#, слабо разбирающимся в SQL и в деталях работы с базами данных.

История развития Entity Framework

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

Впервые Entity Framework появился в 2007 году, а его первая поддержка была обеспечена в Visual Studio 2008, после чего этот API-интерфейс проделал долгий путь и оброс новыми возможностями:

Этапы развития Entity Framework

В первой версии Entity Framework был достаточно ограничен и обеспечивал только базовую реализацию модели ORM на основе подхода Database-First (рассмотрим чуть позже). Версия 4.0 появилась вместе с .NET Framework 4 и Visual Studio 2010 и принесла нам новый подход - Model-First и поддержку POCO-объектов (POCO - Plain Old CLR Object). Вскоре после этого, команда разработчиков Entity Framework выпустила три версии (4.1 – 4.3), в которых поддерживался еще один подход к реализации ORM – Code-First.

Версия 5 Entity Framework вышла вместе с выпуском .NET 4.5 и Visual Studio 2012. Эта версия обеспечивает значительное повышение производительности наряду с поддержкой перечислений, табличных функций, пространственных типов Transact SQL, импорта хранимых процедур, и глубокой интеграцией с ASP.NET MVC.

Текущей версией Entity Framework является 6, в которой появилась поддержка асинхронных запросов и возможность работы с хранимыми процедурами через подход Code-First. Более подробный список изменений в версиях Entity Framework вы можете увидеть на сайте MSDN в статье Entity Framework Version History.

Структура Entity Framework

Теперь давайте кратко рассмотрим некоторые ключевые моменты Entity Framework.

Модель EDM

Entity Framework акцентирует свое внимание на моделировании, в котором вы увидите много знакомых вещей – здесь используются диаграммы ER (entity-relationship, “сущность-отношение”), подход с использованием логического и физического проектирования слоев и многое другое. Ядром Entity Framework является модель EDM (Entity Data Model), суть которой заключается в хранении сущностей (entity) в виде строго типизированных классов, а не в виде объектов схемы базы данных (показано на рисунке ниже). Модель EDM позволяет обеспечить связь между сущностными классами в коде и таблицами базы данных.

Модель EDM

Обратите внимание, что на рисунке выше, таблицы базы данных непосредственно не отображаются на классы сущностей, вместо этого у разработчика есть возможность управлять процессом отображения и он может, например, разбить таблицу на несколько сущностей или наоборот, объединить несколько таблиц в одной сущности (хотя зачастую программисты не используют эту возможность и используют отображение “1 таблица – 1 сущность”).

Слои

Архитектура Entity Framework в абстрактном смысле основана на слоях (layers): рабочий, удаленный и связующий.

Классы с кодом сущностей содержатся в рабочем слое, в котором работают программисты. В зависимости от того, какой подход вы используете (Code-First или DB-First), рабочий слой может быть смоделирован либо с помощью графического дизайнера Visual Studio, либо с помощью кода. После этого у программистов появляется широкий инструментарий для работы с Entity Framework. Синтаксис рабочего слоя описывается с помощью языка Conceptual Schema Definition Language (CSDL).

Удаленный слой определяет таблицы, столбцы, строки, отношения между таблицами базы данных. Синтаксис удаленного слоя описывается с помощью языка Store Schema Definition Language (SSDL).

Связующий слой определяет соответствие между рабочим и удаленным слоями, он связывает свойства сущностного класса в рабочем слое со столбцами таблицы базы данных в удаленном слое. Управлять этим слоем (т.е деталями привязки) можно из окна Mapping Details находящегося в инструментах дизайнера Visual Studio или с помощью аннотаций Fluent API, если вы работаете с подходом Code-First. Язык Mapping Specification Language (MSL) определяет синтаксис связующего слоя.

Важно отметить, что языки CSDL, SSDL и MSL имеют синтаксис XML, но при этом используют разную семантику.

Файлы Entity Framework

Все файлы, используемые в Entity Framework основаны на синтаксисе XML. Использование XML делает файлы простыми и универсальными для других приложений. Также XML-файлы читабельны для человека – вы можете в любой момент открыть и просмотреть содержимое этих файлов. Тем не менее, каждый элемент Entity Framework использует различные файлы XML с различным расширением.

После того как вы создадите новое приложение, которое опирается на Entity Framework и добавите сущностные классы базы данных, вы сможете увидеть результирующие файлы в основной папке проекта (в следующей статье мы более подробно опишем генерацию сущностных классов). В среде Visual Studio 2012 вы найдете единственный файл Entity Data Model XML (.EDMX), хотя в более старых версиях Visual Studio возможно будет создано несколько файлов (один для каждой сущности).

Файл EDMX

Файл EDMX содержит в себе несколько секций, написанных на языках CSDL, SSDL и MSL, представляющих разные слои в архитектуре Entity Framework. Чтобы открыть исходный код этого файла в Visual Studio, щелкните по нему правой кнопкой мыши и выберите в контекстном меню Open With…, после чего в диалоговом окне выберите вариант XML Editor.

Раздел CSDL содержит XML-код, необходимый для построения рабочего слоя:

<!-- CSDL content -->

<edmx:ConceptualModels>

    <Schema Namespace="SampleDbModel" ...>

        <EntityType Name="Employee">

          <Key>

            <PropertyRef Name="Id" />

          </Key>

          

          <Property Name="Id" Type="Int32" Nullable="false" />

          <Property Name="FirstName" Type="String" MaxLength="20" 

                    FixedLength="true" Unicode="true" Nullable="false" />

          <Property Name="LastName" Type="String" MaxLength="20" 

                    FixedLength="true" Unicode="true" Nullable="false" />

          <Property Name="DepartamentNumber" Type="String" MaxLength="4" 

                    FixedLength="true" Unicode="false" />

          

          <NavigationProperty Name="Department" 

                              Relationship="Self.FK_Employee_Department" 

                              FromRole="Employee" ToRole="Department" />

          <NavigationProperty Name="Works_on" 

                              Relationship="Self.FK_Works_on_Employee" 

                              FromRole="Employee" ToRole="Works_on" />

        </EntityType>

        

        <EntityContainer Name="SampleDbEntities" annotation:LazyLoadingEnabled="true">

          <EntitySet Name="Department" EntityType="Self.Department" />

          <EntitySet Name="Employee" EntityType="Self.Employee" />

          <EntitySet Name="Project" EntityType="Self.Project" />

          <EntitySet Name="sysdiagrams" EntityType="Self.sysdiagrams" />

          <EntitySet Name="Works_on" EntityType="Self.Works_on" />

          

          <AssociationSet Name="FK_Employee_Department" Association="Self.FK_Employee_Department">

            <End Role="Department" EntitySet="Department" />

            <End Role="Employee" EntitySet="Employee" />

          </AssociationSet>

          ...

        </EntityContainer>

    </Schema>

</edmx:ConceptualModels>

Обратите внимание, что в CSDL описываются сгенерированные сущности и связи между ними в разделе EntityContainer. В элементах EntityType описывается структура сущностей – имена столбцов и первичные ключи. Обратите внимание на атрибут Type, в котором указывается тип сущности – в данном случае используются .NET-совместимые типы, а не типы T-SQL.

Секция с кодом SSDL описывает структуру таблиц базы данных, их структуру, хранимые процедуры и т.д. Разделы EntityContainer и EntityType аналогичны секции CSDL, но записи опираются на типы данных T-SQL, а не .NET. В примере ниже показана часть секции с кодом SSDL:

<!-- SSDL content -->

<edmx:StorageModels>

      <Schema Namespace="SampleDbModel.Store" ...>

        <EntityType Name="Employee">

          <Key>

            <PropertyRef Name="Id" />

          </Key>

          <Property Name="Id" Type="int" Nullable="false" />

          <Property Name="FirstName" Type="nchar" MaxLength="20" Nullable="false" />

          <Property Name="LastName" Type="nchar" MaxLength="20" Nullable="false" />

          <Property Name="DepartamentNumber" Type="char" MaxLength="4" />

        </EntityType>

        ...

        <EntityContainer Name="SampleDbModelStoreContainer">

          <EntitySet Name="Employee" EntityType="Self.Employee" Schema="dbo" store:Type="Tables" />

          ...

          <AssociationSet Name="FK_Employee_Department" Association="Self.FK_Employee_Department">

            <End Role="Department" EntitySet="Department" />

            <End Role="Employee" EntitySet="Employee" />

          </AssociationSet>

          ...

        </EntityContainer>

      </Schema>

</edmx:StorageModels>

Код MDL связывает сущности, указанные в разделах SSDL и CSDL, и определяет как будут отображаться данные из базы данных на классы .NET. В примере ниже показана часть секции с кодом MDL:

<!-- C-S mapping content -->

<edmx:Mappings>

      <Mapping Space="C-S" xmlns="http://schemas.microsoft.com/ado/2009/11/mapping/cs">

        <EntityContainerMapping ...>

          <EntitySetMapping Name="Employee">

            <EntityTypeMapping TypeName="SampleDbModel.Employee">

              <MappingFragment StoreEntitySet="Employee">

                <ScalarProperty Name="Id" ColumnName="Id" />

                <ScalarProperty Name="FirstName" ColumnName="FirstName" />

                <ScalarProperty Name="LastName" ColumnName="LastName" />

                <ScalarProperty Name="DepartamentNumber" ColumnName="DepartamentNumber" />

              </MappingFragment>

            </EntityTypeMapping>

          </EntitySetMapping>

          ...

        </EntityContainerMapping>

      </Mapping>

</edmx:Mappings>

Подходы для работы с Entity Framework

В Entity Framework поддерживается три подхода к разработке:

Database-First

Подходит для проектировщиков баз данных - сначала вы создаете базу данных с помощью различных инструментов (например, SQL Server Management Studio), а затем генерируете EDMX-модель базы данных, которая предоставляет удобный графический интерфейс для взаимодействия с базой данных в виде диаграмм и объектную модель в виде классов C#. В данном случае вам нужно работать с SQL Server и хорошо знать синтаксис T-SQL, но при этом не нужно разбираться в C#.

Model-First

Подходит для архитекторов - сначала вы создаете графическую модель EDMX в Visual Studio (в фоновом режиме создаются классы C# модели), а затем генерируете на основе диаграммы EDMX базу данных. При данном подходе не нужно знать ни деталей T-SQL ни синтаксиса C#.

Code-First

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

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

Пройди тесты
Лучший чат для C# программистов