Entity Framework
21Работа с базами данных в .NET Framework --- ADO.NET --- Entity Framework
В этой и последующих статьях рассматривается версия Entity Framework 4, основным классом которой является ObjectContext. Если вы хотите быть в курсе последних нововведений в EF посетите раздел нашего сайта, посвященный Entity Framework 6.
Подключенный и автономный уровни ADO.NET снабжают фабрикой, которая позволяет выбирать, вставлять, обновлять и удалять данные с помощью объектов соединений, команд, чтения данных, адаптеров данных и DataSet. Хотя все это замечательно, эти аспекты ADO.NET заставляют трактовать полученные данные в манере, которая тесно связана с физической схемой данных.
Вспомните, например, что при использовании подключенного уровня обычно производится итерация по каждой записи за счет указания имен столбцов объекту чтения данных. С другой стороны, в случае работы с автономным уровнем придется иметь дело с коллекциями строк и столбцов объекта DataTable внутри контейнера DataSet.
При использовании подключенного и автономного уровней ADO.NET всегда приходится помнить о физической структуре лежащей в основе базы данных. Необходимо знать схему каждой таблицы данных, писать сложные SQL-запросы для взаимодействия с данными таблиц и т.д. Это вынуждает писать довольно громоздкий код C#, поскольку C# существенно отличается от языка самой базы данных.
Вдобавок способ конструирования физической базы данных (администратором баз данных) полностью сосредоточен на таких конструкциях базы, как внешние ключи, представления и хранимые процедуры. Сложность баз данных, спроектированных администратором, может еще более возрастать, если администратор при этом заботится о безопасности и масштабируемости. Это также усложняет код C#, который приходится писать для взаимодействия с хранилищем данных.
Платформа ADO.NET Entity Framework (EF) — это программная модель, которая пытается заполнить пробел между конструкциями базы данных и объектно-ориентированными конструкциями. Используя EF, можно взаимодействовать с реляционными базами данных, не имея дело с кодом SQL (при желании). Исполняющая среда EF генерирует подходящие операторы SQL, когда вы применяете запросы LINQ к строго типизированным классам.
LINQ to Entities — это термин, описывающий применение запросов LINQ к сущностным объектам ADO.NET.
Другой возможный подход состоит в том, чтобы вместо обновления базы данных посредством нахождения строки, обновления строки и отправки строки обратно на обработку в пакете запросов SQL, просто изменять свойства объекта и сохранять его состояние. И в этом случае исполняющая среда EF обновляет базу данных автоматически.
В Microsoft считают ADO.NET Entity Framework новым членом семейства технологий доступа к данным, и не намерены заменять им подключенный и автономный уровни. Однако после недолгого использования EF часто отдается предпочтение этой развитой объектной модели перед относительно примитивным миром SQL-запросов и коллекций строк/столбцов.
Тем не менее, иногда в проектах .NET используются все три подхода, поскольку одна только модель EF чрезмерно усложняет код. Например, при построении внутреннего приложения, которому нужно взаимодействовать с единственной таблицей базы данных, подключенный уровень может применяться для запуска пакета хранимых процедур. Существенно выиграть от использования EF могут более крупные приложения, особенно если команда разработчиков уверенно работает с LINQ. Как с любой новой технологией, следует знать, как (и когда) имеет смысл применять ADO.NET EF.
Давайте рассмотрим архитектуру EF:
Составные части архитектуры ADO.NET Entity Framework не столь сложны, как могут показаться на первый взгляд. Давайте рассмотрим их более подробно.
Строго типизированные классы, упомянутые ранее, называются сущностями (entities). Сущности — это концептуальная модель физической базы данных, которая отображается на предметную область. Формально говоря, эта модель называется моделью сущностных данных (Entity Data Model — EDM). Модель EDM представляет собой набор классов клиентской стороны, которые отображаются на физическую базу данных.
Тем не менее, нужно понимать, что сущности вовсе не обязаны напрямую отображаться на схему базы данных, как может показаться, исходя из названия. Сущностные классы можно реструктурировать для соответствия существующим потребностям, и исполняющая среда EF отобразит эти уникальные имена на корректную схему базы данных.
Например, вспомним простую таблицу Inventory, схема которой показана на рисунке:
Если сгенерировать EDM для таблицы Inventory, то по умолчанию сущность будет называться Inventory. Тем не менее, сущностный класс можно переименовать в Car и определить для него уникально именованные свойства по своему выбору, которые будут отображены на столбцы таблицы Inventory. Такая слабая привязка означает возможность формирования сущностей так, чтобы они наиболее точно соответствовали предметной области.
Во многих случаях сущностный класс клиентской стороны называется по имени связанной с ним таблицы базы данных. Однако помните, что вы всегда можете изменить сущность для лучшего соответствия конкретной ситуации.
API-интерфейс EF находится на вершине существующей инфраструктуры ADO.NET. Подобно любому взаимодействию ADO.NET, сущностная платформа использует поставщик данных ADO.NET для взаимодействия с хранилищем данных. Однако поставщик данных должен быть обновлен, чтобы поддерживать новый набор служб, прежде чем он сможет взаимодействовать с API-интерфейсом ЕF. И как можно было ожидать, поставщик данных Microsoft SQL Server уже обновлен соответствующей инфраструктурой, которая полагается на использование сборки System.Data.Entity.dll.
Многие сторонние базы данных (например, Oracle и MySQL) предлагают EF-совместимые поставщики данных. Детальную информацию можно узнать у поставщика системы управления базами данных или просмотреть список известных поставщиков данных ADO.NET.
В дополнение к добавлению необходимых компонентов к поставщику данных Microsoft SQL Server, сборка System.Data.Entity.dll содержит различные пространства имен, которые сами полагаются на службы EF. Две ключевых части API-интерфейса EF, на которые следует обратить внимание сейчас — это службы объектов (object services) и клиент сущности (entity client).
Роль служб объектов
Под службами объектов подразумевается часть EF, которая управляет сущностями клиентской стороны при работе с ними в коде. Службы объектов отслеживают изменения, внесенные в сущность (например, смена цвета автомобиля с зеленого на синий), управляют отношениями между сущностями (скажем, просмотр всех заказов для клиента с заданным именем), а также обеспечивают возможности сохранения изменений в базе данных и сохранение состояния сущности с помощью сериализации (XML и двоичной).
С точки зрения программирования, уровень службы объектов управляет любым классом, расширяющим базовый класс EntityObject. Как и ожидалось, EntityObject представляет цепочку наследования для любых сущностных классов в программной модели EF.
Роль клиента сущности
Вторым важным аспектом API-интерфейса EF является уровень клиента сущности. Эта часть API-интерфейса EF отвечает за работу с поставщиком данных ADO.NET для установки соединений с базой данных, генерации необходимых SQL-операторов на основе состояния сущностей и запросов LINQ, отображения извлеченных данных на корректные формы сущностей, а также управления прочими деталями, которые обычно приходится делать вручную, если не используется Entity Framework.
Функциональность уровня клиента сущности определена в пространстве имен System.Data.EntityClient. Это пространство имен включает набор классов, которые отображают концепции EF (такие как запросы LINQ to Entity) на лежащий в основе поставщик данных ADO.NET. Эти классы (т.е. EntityCommand и EntityConnection) очень похожи на классы, которые можно найти в составе поставщика данных ADO.NET; например, на рисунке ниже показано, что классы уровня клиента сущности расширяют те же абстрактные базовые классы любого другого поставщика:
Уровень клиента сущности обычно работает "за кулисами", но вполне может взаимодействовать с клиентом сущности напрямую, если нужен полный контроль над его действиями (прежде всего, над генерацией запросов SQL и обработкой возвращенных данных из базы).
Если требуется более тонкий контроль над тем, как сущностный клиент строит SQL-оператор на основе входящего запроса LINQ, можно использовать Entity SQL. Это независимый от базы данных диалект SQL, который работает непосредственно с сущностями. Построенный запрос Entity SQL может быть отправлен непосредственно службам клиента сущности (или, при желании, объектным службам), где он будет сформатирован в правильный SQL-оператор для лежащего в основе поставщика данных.
Если требуется более высокая степень контроля над манипуляциями извлеченными результатами, можно отказаться от автоматического отображения результатов базы данных на сущностные объекты и вручную обрабатывать записи с помощью класса EntityDataReader. Как и можно было ожидать, EntityDataReader позволяет обрабатывать извлеченные данные с использованием однонаправленного, доступного только для чтения потока данных, как это делает SqlDataReader.
Роль файла *.edmx
Подводя итог сказанному: сущности — это классы клиентской стороны, которые функционируют, как модель сущностных данных (Entity Data Model). Хотя сущности клиентской стороны в конечном итоге отображаются на таблицу базы данных, жесткая связь между именами свойств сущностных классов и именами столбцов таблиц с данными отсутствует.
В контексте API-интерфейса Entity Framework, чтобы данные сущностных классов отображались на данные таблиц корректно, требуется правильное определение логики отображения. В любой системе, управляемой моделью данных, уровни сущностей, реальной базы данных и отображения разделены на отдельные части: концептуальная модель, логическая модель и физическая модель:
Концептуальная модель определяет сущности и отношения между ними (если есть).
Логическая модель отображает сущности и отношения на таблицы с любыми необходимыми ограничениями внешних ключей.
Физическая модель представляет возможности конкретного механизма данных, указывая детали хранилища, такие как табличная схема, разбиение на разделы и индексация.
В мире EF каждый из этих трех уровней фиксируется в XML-файле. В результате использования интегрированных визуальных конструкторов Entity Framework из Visual Studio 2010 получается файл с расширением *.edmx. Этот файл содержит XML-описания сущностей, физической базы данных и инструкции относительно того, как отображать эту информацию между концептуальной и физической моделями.
Роль классов ObjectContext и ObjectSet<T>
Последним фрагментом мозаики EF является класс ObjectContext, определенный в пространстве имен System.Data.Objects. Генерация файла *.edmx дает в результате сущностные классы, которые отображаются на таблицы базы данных, и класс, расширяющий ObjectContext. Обычно этот класс используется для непрямого взаимодействия со службами объектов и функциональностью клиента сущности.
Класс ObjectContext предлагает набор базовых служб для дочерних классов, включая возможность сохранения всех изменений (которые в конечном итоге превращаются в обновление базы данных), настройку строки соединения, удаление объектов, вызов хранимых процедур, а также обработку других фундаментальных деталей.