Entity Framework что это такое


Оглавление (нажмите, чтобы открыть):

Entity Framework 6

Всем доброго времени суток. В данной первой статье, посвященной Entity Framework, я бы хотел рассказать для чего эта технология нужна и какие преимущества предлагает. Entity Framework — это объектно — реляционный модуль сопоставления, который позволяет разработчикам работать с реляционными базами данных, как с объектами классов. Таблица в базе данных — это класс. Поля таблицы — это свойства класса. Использование данной технологии позволяет оградить программистов от написания большого объёма кода, который обычно требуется для доступа к данным.

Данная технология впервые появилась в 2008 году (версия 1.0), на текущий момент последняя версия — Entity Framework 6. В настоящий момент — это рекомендуемая Microsoft технология для работы с базами данных.

Entity Framework , другими словами, можно назвать библиотекой ORM от Microsoft.

ORM (Object relational mapping) — это объектно-реляционное отображение (сопоставление) — технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая «виртуальную объектную базу данных».

Entity Framework (EF) – это слой абстракции (модель сущностей или, её ещё по-другому называют, концептуальная модель, Entity Data Model (EDM) , которая определяет правила отображения объектов в базе данных.

В EF существует несколько подходов к работе, или по-другому, несколько способов создания этой модели:

Database First – создание модели сущностей и объектной модели (классы) из существующей базы данных. Описание модели сущностей сохраняется в виде xml файла, по которому EF создает модель EDM.

Model First — создание xml-файла модели при помощи дизайнера, на основании которой генерируются база данных и классы (объектная модель).

Code First – написание кода классов при отсутствии модели и БД. Далее на основе этих классов происходит генерация базы данных и модели сущностей EDM.

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

Давайте теперь посмотрим как добавить эту технологию в наш проект. Добавлять будем с помощью менеджера пакетов «Nuget». В проекте выбираем References => «Управление пакетами NuGet» :

Если менеджер пакетов отсутствует — его нужно установить. Его можно найти в Google по запросу «add nuget to visual studio 2013». Либо для Visual Studio 2013 можно скачать по ссылке .

На данном этапе хотелось бы отметить, что иногда менеджер пакетов не может отобразить ни один пакет. Связано это с тем, что у вас скорее всего запущены какие-либо программы по фильтрации трафика. Самый простой вариант в данном случае — это отключить антивирус. Далее в поиске набираем «Entity Framework»:

Нажимаем «Установить». Далее принимаем лицензионное соглашение. После этого Entity Framework устанавливается.

После этого в ссылках проекта мы видим, что Entity Framework был успешно установлен:

В данной статье вы узнали, что такое Entity Framework и научились добавлять его в свой проект.

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

5 аспектов эффективной сохраняемости моделей Entity Framework

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

Около 10 лет назад Эрик Эванс предложил термин «проектирование на уровне доменов» (domain-driven design — DDD) для обозначения нового подхода к разработке программного обеспечения. Метод DDD появился в то время, когда ведущей моделью было проектирование на основе SQL Server. В основном архитекторы строили системы, начиная с оптимизированной (реляционной) модели данных. Все остальное — в частности, бизнес-логика — организовывалось поверх сущностей, идентифицированных в модели данных.

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

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

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

Entity Framework никогда не отличалась четкостью подхода к домену и сохраняемости. Разработчикам никогда не составляло труда следовать любому методу проектирования и сочетать уровень домена с инфраструктурой. В результате платформу Entity Framework можно гибко приспособить для DDD-проектирования (через модель «программный код в первую очередь») и для классического проектирования на основе SQL Server (модель «база данных в первую очередь»). В этой статье мы рассмотрим пять аспектов модели сохраняемости Entity Framework: моделирование с акцентом на программный код и базу данных, сложные типы, типы перечисления (enum), типы массивов и одну таблицу на иерархию.

Моделирование с акцентом на программный код и базу данных

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

Полученная в результате модель функционирует так же, как реальный продукт. Строго говоря, для этого не нужна база данных SQL Server. В большинстве случаев для модели требуется некий уровень сохраняемости, не обязательно в форме базы данных SQL Server. Это может быть и хранилище, отличное от SQL, хранилище событий, комбинация различных хранилищ или уровень удаленных и непрозрачных веб-служб — возможно, база данных в памяти.

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

Совсем иное дело — модель Entity Framework на основе базы данных. Вы берете существующую базу данных SQL Server и выводите из нее модель классов. Благодаря инструментарию Entity Framework это можно сделать также с помощью мастера.

Какой подход лучше и в каких случаях предпочтителен тот или иной метод? Как всегда, ответ на эти вопросы зависит от различных факторов.

Если система проектируется на основе существующей базы данных, и отсутствует возможность внести изменения на уровне сохраняемости, то предпочтительно начинать с базы данных. Но главное при работе с Entity Framework — мыслить в терминах объектов и методов, а не строк и хранимых процедур. Модель можно вывести из существующей базы данных, то есть уровень сохраняемости инвариантен, но старайтесь дополнить объекты бизнес-логикой таким образом, чтобы они выглядели как сущности реального мира. Подход, при котором база данных стоит на первом месте — не просто способ использовать объекты вместо строк данных. Если в конечном итоге вы работаете с классами исключительно со строго типизированными свойствами, то прочитать исходный текст будет наверняка проще, чем при использовании простого ADO.NET, но вы не извлечете никакой выгоды из изменения парадигмы программирования.

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


Сложные типы

Одна из основ DDD — использование типов, которые более удачно описывают задействованные сущности. Это означает, что использование примитивных типов сводится к минимуму, а несколько свойств группируются для формирования агрегированных типов. Классический пример — представление адреса человека или клиента. В подходе на основе базы данных имеются четыре (например) отдельных столбца, таких как адрес, почтовый индекс, город и страна. В случае подхода на основе кода можно иметь тип Address, в котором соединяются перечисленные выше свойства. Но действительно ли целесообразно выбирать этот путь?

Если выбрать подход на основе кода, то цель — как можно более точно моделировать домен. Поэтому сущность Customer («Клиент») имеет адрес, и адрес состоит из улицы, почтового индекса, города и страны. Более того, адрес представляет собой не просто одну-две строки. Адрес может быть связан с конкретными малыми элементами логики, такими как форматирование компонентов или вычисление долготы и широты. Методы класса — идеальное место для размещения этих фрагментов логики.

Сложный тип не является сущностью. У сущности есть идентификатор, тогда как сложный тип при проектировании на уровне доменов — просто агрегирование изолированных данных. Сложный тип даже не обеспечивает собственную сохраняемость; он сохраняется и не читается через службу родительской сущности. Если вас не привлекает перспектива использования сложных типов в модели, то альтернативный вариант — отказаться от такой сущности, как Address. Вместо этого можно использовать непосредственные свойства для составных частей адреса.

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

Типы перечисления

Начиная с Entity Framework 5, можно определить типы перечисления и использовать их, чтобы задать свойства в модели. В подходе DDD типы перечисления играют важную роль, так как с их помощью можно ясно указать действительные значения для данного свойства. Иногда при моделировании обнаруживается, что какое-то свойство определенной сущности имеет целочисленное значение, и, следовательно, ему назначается тип Int32. Но очень редко бывает, что допустимые значения занимают весь диапазон целых чисел. Конечно, можно организовать фильтрацию на уровне проверки, но не будет ли это излишним усложнением? Если удастся удачно моделировать свойство, то дополнительной проверки не потребуется. Это оптимальный подход, но одновременно и наглядный пример того, как теория DDD противоречит практике Entity Framework.

Платформа Entity Framework поддерживает тип перечисления начиная с версии 5, но необходимо компилировать приложение для. NET 4.5. Ситуация немного улучшилась с появлением Entity Framework 6, поскольку в рамках подхода на основе программного кода можно без проблем использовать в модели свойства с типом перечисления:

В данном случае тип — сложный, и все свойства выводятся как простые перечисления. NET. В SQL Server сохраняются целые числа, скрытые за перечислениями. При чтении из хранилища целые числа преобразуются в элементы перечисления.

Что делать, если по какой-то причине невозможно применить. NET 4.5 или подход на основе программного кода? В этом случае можно прибегнуть к перечислениям. С помощью этого же приема можно работать с массивами.

Типы массива

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

Свойство FaultsTeam1 — массив типа Fault, в котором каждый элемент массива соответствует игроку команды. Недостаточно просто предоставить свойство get/set. Это приемлемо в модели, но вряд ли может быть реализовано в Entity Framework. Чтобы обойти проблему, можно объявить дополнительное свойство — в данном случае оно именуется InternalFaultsTeam1 — строкового типа. Это простое свойство, успешно обрабатываемое в Entity Framework.

Пара методов получения/задания в FaultsTeam1 обеспечивает чтение и запись свойства InternalFaultsTeam1 каждый раз, когда используется официальный API-интерфейс для нарушений. Тип Fault может содержать информацию об игроке и подробности о нарушении. Ради простоты в образцовом исходном тексте предполагается, что о Fault известно лишь, что это целое число, представляющее количество нарушений для игрока. Игроки идентифицируются индексом, поэтому первый элемент списка — первый игрок команды, и т.д. Сериализованный список нарушений представляет собой строку с разделителями в виде запятых. При сопоставлении модели с механизмом сохраняемости Entity Framework вы сопоставляете InternalFaultsTeam1, но Entity Framework получает указание игнорировать FaultsTeam1. Сопоставление можно выполнить как через текущий API, так и через заметки к данным, как показано в следующем исходном тексте:

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

Это тот же прием, который можно задействовать в. NET 4.0 при использовании перечисляемых типов с версией Entity Framework, в которой нет собственной поддержки типов перечисления. Вы определяете внутреннее целочисленное свойство для хранилища и предоставляете несопоставленное свойство перечисления, метод получения/задания которого выполняет преобразование в/из внутреннего буфера.

Одна таблица на иерархию

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

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

Если сущности связаны через наследование, то можно применить несколько подходов. Подход по умолчанию, одна таблица на иерархию (Table-per-Hierarchy, TPH), предусматривает, что все классы в иерархии сопоставляются одной таблице. Иначе можно иметь отдельные таблицы, по одной для типа. Этот подход известен как»одна таблица на тип«(Table-per-Type, TPT) и для функционирования он требует текущего кода:

Еще один подход строится на основе одной физической таблицы на конкретный (не абстрактный) тип в иерархии Table-Per-Concrete Type Inheritance, TPC). Этот подход требует следующего явного кода текущего API, в котором выполняется импорт унаследованных свойств из базового класса с последующим созданием таблицы для производного типа.

Если использовать способ проектирования на основе программного кода, то код сопоставления находится в переопределяемом методе OnModelCreating, заданном в пользовательском классе контекста.

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

Основной стимул внедрения DDD и отказа от баз данных как центрального элемента при проектировании — увеличение сложности бизнес-доменов. Если ваша модель, в сущности, мало отличается от CRUD (создание, чтение, обновление, удаление), то вряд ли следует брать на вооружение DDD при отсутствии полной уверенности в своих силах. Однако DDD обеспечивает достоверные модели, и даже CRUD можно более корректно моделировать с использованием DDD.

Поделитесь материалом с коллегами и друзьями

Новые возможности в июньской CTP-версии Entity Framework

Срикант Мандади

Продукты и технологии:

Entity Framework 4.2, Visual Studio 2010

В статье рассматриваются:

  • новые средства — перечислимые, табличные функции (table-valued functions) и пространственные типы;
  • использование подходов Code First и Database First;
  • автоматически компилируемые LINQ-запросы.


Недавно выпущенная CTP-версия Microsoft Entity Framework (EF) за июнь 2011 г. включает поддержку ряда средств, о введении которых нас часто просили, в частности перечислимых и пространственных типов, а также функций, возвращающих табличные значения (table-valued functions, TVF) (далее для краткости — табличные функции). Мы рассмотрим эти средства на простых примерах. Я исхожу из того, что вы знакомы с EF (http://bit.ly/oLbjp0) и шаблоном разработки Code First (http://bit.ly/oQ77Hm), введенным в EF 4.1.

Вот что вам понадобится для работы с примерами в этой статье:

  • Visual Studio 2010 Express и SQL Server 2008 R2 Express или выше. Редакции Express продуктов Visual Studio и SQL Server можно скачать по ссылке bit.ly/rsFvxJ.
  • Microsoft EF и EF Tools June 2011 CTP
  • база данных Northwind; ее можно скачать по ссылке bit.ly/pwbDoQ.

Перечислимые типы

Начнем с одного из самых часто запрашиваемых средств в EF — перечислимых. Многие языки программирования, в том числе .NET-языки вроде C# и Visual Basic, изначально поддерживают перечислимые типы. В EF поставлена цель разрешить разработчикам создавать перечислимые типы в своих CLR-типах и сопоставлять с нижележащей Entity Data Model (EDM), после этого сохранять соответствующие значения в базе данных. Прежде чем углубиться в детали, рассмотрим простой пример. Перечислимые поддерживаются в Code First, Database First и Model First. Я начну с подхода Database First (сначала база данных), а затем покажу пример, где используется подход Code First.

Для примера Database First воспользуемся таблицей Products в базе данных Northwind. Прежде чем добавлять модель, переключитесь на EF June 2011 CTP. Для этого сделайте следующее.

  1. Запустите Visual Studio 2010 и создайте новый проект C# Console Application.
  2. Щелкните свой проект правой кнопкой мыши в Solution Explorer и выберите Properties.
  3. Выберите Microsoft Entity Framework June 2011 CTP из раскрывающего списка Target framework (рис. 1).
  4. Нажмите Ctrl+S, чтобы сохранить проект. Visual Studio предложит закрыть проект и заново открыть его — согласитесь, щелкнув Yes.
  5. Добавьте новую модель в проект, выбрав Project | Add New Item (или нажав Ctrl+Shift+A) и указав ADO.NET Data Entity Model в Visual C# Items (мы назовем нашу модель «CTP1EnumsModel.edmx»), затем щелкните Add.
  6. С помощью мастера укажите базу данных Northwind. Выберите таблицу Products и щелкните Finish.
  7. В Entity Model, которая получится в результате такого выбора, содержится одна сущность (Product), как показано на рис. 2.
Мастер Йода рекомендует:  Каталог панорам для 3D графики HDRI Haven стал бесплатным

Рис. 1. Ориентация на Entity Framework June 2011 CTP

Рис. 2. Entity Model для сущности Product

Ниже приведен LINQ-запрос для получения всех продуктов, относящихся к категории Beverages. Заметьте, что CategoryID для Beverages равен 1:

Конечно, чтобы написать этот запрос, вы должны были бы знать, что CategoryID для Beverages равно 1, что возможно лишь в двух случаях: вы запомнили это значение или нашли его, проанализировав базу данных. Другая проблема с этим запросом в том, что непонятно, какую категорию запрашивает этот код. В таком случае нужно либо документировать категорию в каждом месте, где используется CategoryID, либо иметь каждому, кто читает этот код, соответствующие знания о значениях CategoryID для различных категорий.

Еще одна проблема вылезает, когда вы пытаетесь вставить новый Product. Для вставки в таблицу Products используйте следующий код:

Запустив этот код, вы получите от базы данных исключение из-за ограничения внешнего ключа. Это исключение генерируется потому, что категории с идентификатором 13 нет. Было бы куда лучше, если бы у программиста был какой-то способ выяснить список категорий и назначить правильный идентификатор вместо того, чтобы все время помнить набор правильных целочисленных значений.

Давайте введем в модель перечислимые и посмотрим, насколько эту улучшит ситуацию.

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

  1. Откройте модель в дизайнере, дважды щелкнув файл CTP1EnumsModel.edmx.
  2. Щелкните правой кнопкой мыши свойство CategoryID в Product Entity и выберите Convert to Enum.
  3. 3. Создайте перечислимый тип (enum) и введите значения для его членов в новом диалоге, который появится на экране (рис. 3). Присвойте этому типу имя Category и выберите Byte в качестве нижележащего типа. Нижележащим считается тип, который предоставляет пространство значений для перечислимого типа. Вы можете выбирать его на основе количества членов в перечислении. В данном перечислении восемь членов, что как раз и соответствует байту. Введите эти члены в порядке возрастания значений CategoryID. Укажите Value для первой категории (Beverages) как 1 и оставьте поле Value для остальных членов пустым, потому что их значения автоматически увеличиваются на 1 в базе данных. Этот вариант и для EF является поведением по умолчанию. Но, если бы значения в базе данных были другими, вам пришлось бы заполнять поле Value для каждой категории. Если бы значение для Beverages было 0 вместо 1, вы также могли бы оставить остальные поля пустыми, так как EF выбирает 0 в качестве значения по умолчанию для первого члена перечисления.
  4. Создавая перечислимый тип, вы можете обозначить его как флаг, используя параметр «Is Flag?». Он используется только при генерации кода; если этот флаг установлен, перечислимый тип будет сгенерирован с атрибутом Flags (подробнее о таких перечислениях см. по ссылке bit.ly/oPqiMp). В этом примере оставьте данный параметр неустановленным.
  5. Перекомпилируйте приложение для повторной генерации кода, и полученный в результате этого код будет теперь включать перечислимые.

Рис. 3. Окно для создания перечислимого типа

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

Теперь IntelliSense будет помогать в написании запроса, и вам не придется изучать базу данных в поисках значений Beverages. Аналогично при обновлениях IntelliSense будет показывать корректные значения для Category.

Мы только что рассмотрели перечислимые, используя подход Database First. А сейчас я применю подход Code First для написания запроса, который возвращает все продукты категории Beverages с использованием перечислимых. Для этого создайте еще одно консольное приложение и добавьте файл исходного кода на C# с типами, показанными на рис. 4..

Рис. 4. Применение перечислимых в подходе Code First

Класс EnumsCodeFirstContext наследует от DbContext — нового типа в EF 4.1, аналогичного ObjectContext, но гораздо более простого в использовании. (Подробнее о применении DbContext API см. по ссылке bit.ly/eeEsyt.)

В коде на рис. 4 стоит обратить внимание на пару моментов.

  • Атрибут Column над свойством Category используется для сопоставления CLR-свойств и столбцов, когда у них разные имена или типы.
  • Конструктор в EnumsCodeFirstContext вызывает конструктор базового класса, передавая строку подключения. По умолчанию DbContext создает базу данных в локальном экземпляре SqlExpress с полным именем класса, производного от DbContext. В этом примере мы просто используем существующую базу данных Northwind.

Теперь вы можете написать код, аналогичный тому, который использовался в контексте Database First, чтобы получить все продукты, относящиеся к категории Beverages:

Другое важное средство, добавленное в эту CTP-версию, — поддержка табличных функций.

Табличные функции

Другое важное средство, добавленное в эту CTP-версию, — поддержка табличных функций (TVF). TVF очень похожи на хранимые процедуры с одним важным отличием: результат, возвращаемый TVF, является компонуемым (composable). Это означает, что результаты от TVF можно использовать во внешнем запросе. Таким образом, главное для разработчиков, использующих EF, заключается в том, что TVF можно указывать в LINQ-запросе, а хранимую процедуру — нет. Я продемонстрирую пример использования TVF в EF-приложении. Попутно вы увидите, как задействовать преимущества функциональности полнотекстового поиска (Full-Text Search, FTS) в SQL Server (подробнее см. по ссылке bit.ly/qZXG9X).

Функциональность FTS предоставляется через несколько предикатов и TVF. В предыдущих версиях EF вы могли задействовать полнотекстовые TVF, либо вызывая их в скрипте на T-SQL с применением ExecuteStoreCommand, либо используя хранимую процедуру. Но оба этих механизма не обеспечивают компонуемость, и их нельзя применять в LINQ to Entities. В моем примере вы увидите, как задействовать эти функции в качестве компонуемых с поддержкой TVF в этой CTP-версии. Для этого я позаимствовал запрос из документации MSDN для ContainsTable (bit.ly/q8FFws). Этот запрос ищет все названия продуктов, в которых есть слова «breads», «fish» или «beers», и этим словам назначаются разные весовые доли (значимость). Для каждой полученной строки, отвечающей этим критериям поиска, показывается относительная близость совпадения (классификационное значение):


Попробуем написать тот же запрос в LINQ to Entities. К сожалению, предоставить ContainsTable напрямую EF нельзя, так как эта инфраструктура ожидает, что в первых двух параметрах имена таблицы и столбца передаются как идентификаторы без кавычек, т. е. как Categories, а не ‘Categories’, и нет никакого способа сообщить EF особым образом интерпретировать эти параметры. Чтобы обойти это ограничение, оберните ContainsTable в другую пользовательскую TVF. Выполните следующий SQL-код для создания TVF с именем ContainsTableWrapper (TVF выполняет функцию ContainsTable применительно к столбцу Description в таблице Categories):

Теперь создайте EF-приложение и используйте эту TVF. Придерживайтесь той же схемы, что и в примере с перечислением, чтобы создать консольное приложение и добавить модель сущностей, связанную с Northwind. Включите Categories, Products и только что созданную TVF. Модель будет выглядеть, как показано на рис. 5.

Рис. 5. Модель сущностей с Products и Categories из Northwind

TVF в рабочей области дизайнера не отображается, но вы можете увидеть ее в Model Browser, раскрыв Stored Procedures/Functions в разделе Store.

Чтобы задействовать эту функцию в LINQ, добавьте функцию-заглушку (function stub) (как описано по ссылке bit.ly/qhIYe2). Я добавил функцию-заглушку в частичный класс для класса ObjectContext — в данном случае NorthwindEntities:

Теперь вы можете пользоваться этой функцией в своих запросах. Просто выведите в консоль Key, т. е. CategoryId и Rank для полнотекстового запроса, упомянутого ранее:

Обзор ADO.NET Entity Framework

Written on 13 Февраля 2009 . Posted in ADO.NET и базы данных

ОГЛАВЛЕНИЕ

Entity Framework представляет логическую структуру базы данных, используя концептуальный слой, слой сопоставления и логический слой. В этой статье я рассмотрю задачи каждого из этих слоев. Я также представлю поставщика данных EntityClient и новый язык, Entity SQL, который может взаимодействовать с сущностной моделью данных (Entity Data Model, EDM) концептуального слоя.

Альтернативой поставщику данных EntityClient являются службы Object Services. Конкретнее, Object Services в Entity Framework могут помочь уменьшить количество кода для доступа к данным, который приходится писать разработчикам. Я также обсуждаю и показываю, как использовать Object Services совместно с Entity SQL и LINQ (запрос, встраиваемый в язык) для Entities для взаимодействия с EDM и извлечения концептуальных сущностей.

Компоненты Entity Framework

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

Entity Framework создает концептуальную модель, для которой разработчики пишут код. К этой модели можно обращаться напрямую, используя новый поставщик данных EntityClient и новый язык (похожий на T-SQL), называемый Entity SQL. Модель EntityClient схожа с привычными объектами ADO.NET, он использует объекты EntityConnection и EntityCommand, чтобы возвратить DbDataReader. Другим вариантом для разработчиков является задействование Object Services с использованием либо объекта ObjectQuery и Entity SQL, либо LINQ to Entities. Object Services позволяют разработчикам воспользоваться построенными на основе концептуальной модели классами, предлагающими возможности по строгой типизации и постоянству (см. рис. 1).

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

Такие способы доступа к данным позволяют разработчику взаимодействовать с концептуальными сущностями EDM. Слои EDM существуют в виде XML-файлов; на сегодня EDM можно создать вручную при помощи средства командной строки (EDMGEN.EXE) или при помощи мастера Visual Studio.

Сущностная модель данных

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

  • Концептуальный слой
  • Слой сопоставления
  • Логический слой

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

Рис. 2 Разработка сущностной модели данных

Концептуальная модель определяется в XML-файле с использованием языка определения концептуальной схемы (Conceptual Schema Definition Language, CSDL). CSDL определяет сущности и взаимоотношения в том виде, в каком они представлены в бизнес-слое приложения. Логическая модель, представляющая схему базы данных, определяется в XML-файле с использованием языка определения схемы хранилища (Store Schema Definition Language, SSDL). Например, в концептуальной модели может быть сущность, на самом деле получающая данные из нескольких таблиц базы данных. Концептуальная и логическая модели могут связывать сущности взаимно-однозначно. Однако преимущество EDM в том, что это не обязательно. Слой сопоставления, определяемый с использованием языка схемы сопоставления (Mapping Schema Language, MSL), сопоставляет два остальных слоя друг другу. Это сопоставление и позволяет разработчикам программировать для концептуальной модели и сопоставлять инструкции логической модели.

Создание сущностной модели данных

Вы можете создать EDM, используя базу данных в качестве отправной точки. Затем можно изменить XML вручную (или, возможно, при помощи средства моделирования, которое может быть доступно в следующем выпуске Visual Studio). Когда вы добавляете к вашему проекту EDM ADO.NET, мастер проходит процесс создания EDM по шагам.

После того как вы выбрали для создания EDM тестовую базу данных Northwind, поставляемую с «Orcas», вам предоставляется список объектов, которые возможно смоделировать, как показано на рис. 3. Я выбрал вариант включить все таблицы в модель, поэтому мастер создает файлы CSDL, SSDL и MSL для всех таблиц в Northwind. Конечно, это взаимно-однозначное сопоставление таблиц сущностям. Я могу изменить сопоставление для соответствия моим бизнес-нуждам, комбинируя сущности или используя наследование.

Рис. 3 Мастер EDM

Мастер также создает набор классов, основываясь на CSDL, представляющем модель. Часть этих классов показана на рис. 4 в окне просмотра классов. Из-за того, что я начал со взаимно-однозначного сопоставления, для каждой таблицы есть по классу. Мастер EDM отследил связь между таблицами Customers и Orders в базе данных и создал соответствующую ассоциацию в концептуальной модели. Поэтому класс Customers содержит свойство перемещения Orders, позволяющее разработчикам переходить от экземпляра класса Customers к любому из экземпляров класса Orders для него.

Разбор CSDL

Метаданные, содержащиеся в CSDL-файле, содержат списки сущностей, представленных элементами EntityType, и связей, представленных элементами Association, относящихся к типу AssociationType (обратите внимание, что в схеме именования в выпуске Beta 1 есть несоответствия). На рис. 5 показан фрагмент CSDL-файла, который я создал ранее. Сущности содержат списки скалярных свойств, определяющих их. Атрибут Key показывает, какие свойства являются ключевыми. Составные ключи выделяются разделением имен свойств пробелами. Сущности также могут содержать специальные свойства, называемые NavigationProperty. Они определяют переходы от одной сущности к другой через ассоциации.

Figure 5 Определение EntityType в CSDL

В следующем фрагменте CSDL определятся AssociationType между Customer и относящимися к нему Orders:


Элементы End в AssociationType указывают участвующих в ассоциации. В этом примере сущность Customers ассоциирована с сущностью Orders. Также сущность Customers может быть связана с любым числом сущностей Orders, что определяется атрибутом Multiplicity.

В то время как элементы EntityType и AssociationType определяют типы сущностей области и отношения между ними, элементы EntitySet и AssociationSet определяют их области применения. Все «наборы», которые должны быть сгруппированы вместе, содержатся внутри элемента EntityContainer. (Полный CSDL приведен в файле NorthwindEntities.csdl в прилагающейся загрузке).

Следующий фрагмент CSDL демонстрирует EntityContainer и часть его содержимого:

Этот фрагмент включает наборы EntitySet для типов EntityType Customers и Orders: Здесь же объявляется ассоциация AssociationSet FK_Orders_Customers. Таким образом, этот фрагмент определяет сущности Customers и Orders, а также связь между ними.

Сопоставление хранилищу

Файл SSDL определяет структуру реляционных данных в базе данных. В нем также используются элементы XML EntityType и AssociationType, в этом случае для объявления структур таблиц и существующих в базе данных внешних ключей соответственно. Пространство имен файла SSDL основано на имени базы данных, использованной в EDM, тогда как элемент EntityContainer назван в соответствии со схемой базы данных. EntityContainer содержит наборы элементов EntitySet и AssociationSet, которые объявляют экземпляры таблиц и отношений, представленных элементами EntityType и AssociationType. Каждому набору EntitySet в файле SSDL соответствует таблица в базе данных.

Если вы создадите EDM на основе базы данных и немедленно откроете файлы CSDL и SSDL, не внося изменений, вы увидите, что они удивительно похожи. Это потому, что модели созданы прямо из базы данных, и концептуальная модель сопоставляется логическому хранилищу напрямую. Файл MSL содержит прямое соответствие CSDL и SSDL. Все запросы на основе такой EDM транслируются в созданные команды SQL. Entity Framework также поддерживает использование хранимых процедур вместо создания запросов SQL.

Для сопоставления модели (CSDL) хранилищу (SSDL) используется элемент EntityContainerMapping. Атрибут StorageEntityContainer показывает название контейнера EntityContainer в хранилище, а атрибут EdmEntityContainer показывает соответствующий EntityContainer в модели. Для сопоставления набора EntitySet модели набору EntitySet хранилища требуется элемент EntitySetMapping. Атрибут Name определяет название набора EntitySet модели, а атрибут TableName определяет название соответствующего набора EntitySet в хранилище. Каждое свойство модели сопоставляется хранилищу посредством элемента ScalarProperty. На Рис. 6 показан фрагмент файла MSL.

Figure 6 Сопоставление унаследованной сущности в MSL

Определение наследования

EDM также поддерживает модели, не соответствующие базе данных взаимно-однозначно. Например, используя базу данных Northwind, вы можете создать класс, называющийся DiscontinuedProducts, который наследует все свойства класса Products, но содержит только продукты, значение поля Discontinued для которых равно 1. (Отметьте, что класс DiscontinuedProducts мог бы также иметь дополнительные свойства). Это упрощенная схема наследования, но она показывает, как применить наследование в EDM.

Первым шагом по созданию класса DiscontinuedProducts в концептуальной модели является открытие файла CSDL, создание нового типа EntityType, называющегося DiscontinuedProducts, и установка его атрибута BaseType в значение NorthwindModel.Products (схема и название базового EntityType). Порожденный тип EntityType наследует свойства EntityType Products, включая ключи. Поэтому я не указываю атрибут Key и свойства для произведенного EntityType. Я также убираю свойство Discontinued из EntityType Products. Дополнительный код CSDL для всего описанного выглядит так:

Следующим шагом в этом процессе является открытие файла MSL и удаление атрибутов TypeName и TableName элемента EntitySetMapping Products. Теперь они будут устанавливаться отдельно для каждого конкретного типа EntityType. Затем необходимо создать дочерний элемент EntityTypeMapping и установить TypeName как NorthwindModel.Products. Для каждого EntityType, порожденного от базового EntityType, EntitySetMapping должен включать элемент EntityTypeMapping. Далее нужно создать дочерний элемент EntityTypeMapping, называющийся TableMappingFragment, и установить для его атрибута TableName значение Products. В целом, эти шаги переносят сопоставление с элемента EntitySetMapping на более низкий и детальный уровень.

Закомментируйте сопоставление свойства Discontinued и добавьте элемент Condition, указывающий, что включены будут только записи со значением поля Discontinued, равным 0. Скопируйте целиком XML фрагмент EntityTypeMapping, поменяйте значение атрибута Name на DiscontinuedProducts и поменяйте значение в условии на 1. Новый фрагмент файла MSL приведен на Рис. 6.

Сопоставление нескольким таблицам

Другим способом уйти в EDM от строгого взаимно-однозначного сопоставления модели хранилищу является сопоставление одной сущности в модели нескольким таблицам в хранилище. Между таблицами Contacts и ContactNameSplit в базе данных Northwind есть взаимно-однозначная связь, и можно объединить их в одну сущность в модели. Для примера я создам в модели сущность, включающую все поля таблицы Contacts и поля Title и Name из таблицы ContactNameSplit.

Первым изменением является добавление двух дополнительных свойств в элементе EntityType Contacts в файле CSDL: Name и Title.

Дальнейшие изменения более описательны. Эти два новых свойства в модели теперь должны быть сопоставлены хранилищу в файле MSL. Необходимо изменить элемент EntitySetMapping для EntitySet Contacts, чтобы представлять сопоставление нескольким таблицам. В этом примере я изменил существующий тег EntitySetMapping для EntitySet Contacts, удалив атрибуты TableName и TypeName. Эти атрибуты объявляются в элементе EntitySetMapping, только если набор EntitySet в модели взаимно-однозначно сопоставлен набору EntitySet в хранилище.

Поскольку сопоставление набора EntitySet модели набору EntitySet хранилища для Contacts было удалено, необходимо создать ему замену. Такой заменой является дочерний элемент EntityTypeMapping. Их необходимо создать два – по одному для представления каждой из таблиц Contacts и ContactNameSplit в хранилище. Элементы EntityTypeMapping определяют атрибут TypeName для каждого из наборов EntitySet.

Мастер Йода рекомендует:  Крупные компании поддержали экосистему для разработки ИИ от Microsoft и Facebook

Внутри каждого из элементов EntityTypeMapping помещен дочерний элемент, называющийся TableMappingFragment. Этот элемент включает атрибут TableName, соответствующий набору EntitySet в хранилище. В TableMappingFragment определены все элементы ScalarProperty, сопоставляющие свойства модели хранилищу. На Рис. 7 показан обновленный элемент EntitySetMapping Contacts, который теперь сопоставляет таблицы Contacts и ContactSplitName хранилища одному набору EntitySet модели.

Figure 7 Объединение таблиц в сущность

Использование EntityClient

Доступ к концептуальной модели Entity Framework может быть организован тремя способами (см. Рис. 1). Здесь я представлю EntityClient, новый поставщик данных .NET.
EntityClient абстрагирован от логического хранилища, поскольку он взаимодействует с концептуальной моделью посредством своего собственного текстового языка, называющегося Entity SQL. Все запросы Entity SQL, выполняемые через EntityClient, компилируются в деревья команд, посылаемые в хранилище. Преобразование запросов Entity SQL через концептуальную модель и далее в хранилище обеспечивается Entity Framework.

Классы EntityClient похожи на классы распространенных поставщиков ADO.NET. Например, запросы EntityClient выполняются в объекте EntityCommand, которому необходим объект EntityConnection для подключения к EDM. Хотя EntityClient взаимодействует с сущностями EDM, он не возвращает экземпляры сущностей, а вместо этого возвращает все результаты в виде объекта DbDataReader. При помощи DbDataReader EntityClient может возвращать стандартный набор строк и столбцов, либо представление более сложной иерархии данных.

На Рис. 8 показан пример использования EntityClient для подключения к концептуальной модели и получения списка заказчиков из Лондона. EntityConnection может воспринимать полную строку подключения к концептуальному слою или ее название в файле App.Config. Строка подключения содержит перечень файлов метаданных (файлов CSDL, MSL и SSDL), а также строку подключения к хранилищу, зависящую от конкретной базы данных. Здесь приведен пример полной строки подключения для Рис. 8:

Figure 8 Использование Entity SQL в EntityClient для доступа к EDM

Пример кода на Рис. 8 показывает, как создать объект EntityConnection и выполнить для него команду EntityCommand. Запрос, написанный на Entity SQL, обращается к набору EntitySet Customers в EDM. Отметьте, что синтаксис специально сделан аналогичным синтаксису T-SQL. (Если вам нужен хороший справочник по синтаксису Entity SQL, воспользуйтесь документацией MSDN® для первого бета-выпуска «Orcas».)

Как показано на Рис. 8, объекты EntityParameter также могут быть добавлены. В первом бета-выпуске EntityClient не поддерживает запросов DML; однако, ведется работа на поддержкой этого в будущем. Тем не менее, DML можно выполнить другим способом, таким как LINQ to Entities.

Использование служб Object Services

Другим способом взаимодействия с данными, представленными EDM, является использование служб Object Services. Службы Object Services предоставляют возможность загружать объекты и следовать любым связям, определенным в EDM. Как показано на Рис. 1, службы Object Services используют EntityClient для получения данных. Службы Object Services добавляют разрешение идентификаторов, что при использовании DataSet приходится делать вручную. Они также обеспечивают неизменность объектов и отслеживание изменений через события, чтобы позволять явные загрузку и сохранение. За счет этого снижается число обращений к серверу.

Службы Object Services позволяют возвращать списки объектов напрямую – можно возвращать как проекции, так и определенные сущности. Например, пользуясь Object Services, можно получить List , как определено в EDM. Объекты Customers можно просмотреть, изменить значения, а затем сохранить данные в базе данных.

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

Можно использовать службы Object Services для выполнения запросов Entity SQL или можно писать запросы, используя LINQ to Entities. Следующий пример демонстрирует запрос на Entity SQL, выполняемый через службы Object Services для получения списка заказчиков:


В EDM EntityContainer представлен классом, производным от ObjectContext (в этом примере northwindContext). Класс ObjectContext реализует интерфейс ObjectQuery , позволяя создавать запросы, используя Entity SQL и LINQ.

Метод CreateQuery принимает параметризованный оператор Entity SQL, определяющей запрос, возвращающий список сущностей Customers. Собственно выражение SQL, обращающееся к базе, выполняется при итерации по ObjectQuery оператором foreach.

Использование LINQ to Entities

С помощью служб Object Services можно выполнять динамические запросы, написанные на Entity SQL, для взаимодействия с сущностями EDM. Но в Entity Framework также можно работать со строго типизированными классами EDM, используя LINQ to Entities. Например, в только что продемонстрированном примере запрос на Entity SQL через Object Services может быть изменен для выполнения на LINQ to Entities, вот так:

В этом примере кода весь основанный на тексте синтаксис Entity SQL заменен на строго типизированный синтаксис LINQ, поддерживаемый в C# 3.0. Более подробная информация о LINQ и его поддержке в C# и Visual Basic® доступна в июньском выпуске MSDN Magazine за 2007 г. по адресу msdn.microsoft.com/msdnmag/issues/07/06.

Теперь вспомните, как я создал в EDM тип EntityType, называющийся DiscontinuedProducts, произведенный от Products. Возможности EDM по наследованию могут быть использованы совместно с LINQ и Object Services для получения списка продуктов, которые больше не поддерживаются. Обратите внимание, что в следующем примере не указывается, что значение поля Discontinued должно быть равно 1. Вместо этого, тип для сущности продукта сверяется с производным EntityType DiscontinuedProducts, что в свою очередь задействует условие, которое я создал в сопоставлении (файле MSL), чтобы создать подходящее выражение SQL для получения только неподдерживаемых продуктов:

Вы можете также создавать запросы, использующие преимущества встроенных отношений EDM (определяемых набором AssociationSet). Например, список заказов для заказчиков из Лондона может быть получен посредством следующего выражения запроса LINQ:

Этот пример кода начинается с сущности Orders и использует ее свойство перемещения Customers для просмотра свойства City. Заказы от заказчиков не из Лондона полностью отфильтровываются. Поскольку возвращается список сущностей Orders, сущности могут быть изменены, и изменения могут быть сохранены в базе данных. Сохранение изменений в базе данных может быть выполнено при помощи метода SaveChanges.

Следующий пример получает список заказчиков из Лондона и устанавливает значение свойства Country для каждого из них в «United Kingdom». Изменения сохраняются в StateManager, но не заносятся в базу данных, пока не вызывается метод SaveChanges:

Вы также можете создать новый экземпляр сущности и добавить его в EDM, используя метод AddObject объекта ObjectContext. В следующем примере показано, как добавить новую категорию в таблицу базы данных Categories:

Сперва создается экземпляр сущности Categories и устанавливается значение его свойства CategoryName. Затем новая категория добавляется в EDM вызовом метода AddObject. Когда вызывается метод SaveChanges, создается оператор SQL, который сохраняет новую Category в базе данных и возвращает идентификатор CategoryID для новой строки.

Когда между сущностями есть связи, вам может потребоваться ассоциировать новую сущность с уже существующей. Например, можно создать новую сущность Orders и связать ее свойство Customers с существующей сущностью Customers. Хотя в таблице Orders в базе данных есть поле CustomerID, EDM представляет эту связь в объектно-ориентированном стиле, используя свойство Customers для обращения к существующей сущности Customers:

Заключение

Entity Framework позволяет разработчикам обращаться к данным, используя объектную модель вместо логической или реляционной модели данных. Разработав EDM и сопоставление реляционному хранилищу, можно взаимодействовать с объектами различными способами: EntityClient, ObjectServices и LINQ.

Общие сведения о Entity

Дата изменения: 12.10.2020

Entity – набор технологий, который обеспечивает разработку .NET приложений с использованием доступа к базам данных.

Логически Entity – отдельный Фреймворк, физически – набор связанных сборок, входящих в общий пакет .NET Framework.

Проблема, которую решает Entity – это разнородность данных в базах и данных используемых в коде.

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

Entity позволяет программисту обращаться к сущностям (таблицам) баз данных, как к объектам, к столбцам сущностей – как к свойствам объекта, а к ячейкам сущностей – как к значениям свойств. Такой подход называется объектно-реляционным отображением (object-relational mapping — ORM). Entity – это реализация ORM подхода от Microsoft.

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

Но что делать, когда одному классу на C# соответствует две или более сущности реляционной базы данных или наоборот сущность одна, а классов, приставляющих ее несколько?

Как устроен

Entity решает проблему несоответствия типов путем внедрения посредника между реляционной базой данных и классом в .NET. Посредник – это абстрактная модель EDM (Entity Data Model).

Она хранит информацию о таблицах, столбцах и связях в виде строготипизированых классов. В приложениях, где модель предметной области – это база данных, каким бы подходом вы не пользовались вы будете работать с моделью EDM. Проектирование новой БД – это моделирование, и объявление классов C# — тоже моделирование.

Схема сопоставления данных

Как работает

Вся этапы работы с Entity делятся на два вида:

  • моделирование;
  • доступ к моделям и сущностям для изменений.

Моделирование


Традиционный подход к разработке модели предметной области – это последовательная конкретизация модели.

  • Модель домена;
  • Логическая модель БД;
  • Физическая модель БД.

Модель домена – определяет какие таблицы будут в БД и как они будут связаны. Это самая высокая абстракция.

Логическая модель – включает информацию о ключах таблиц и всех ограничениях –это нормализованная модель.

Физическая – определяет в каких файлах хранятся таблицы и как эти файлы хранятся на сервере.

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

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

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

Entity это изменил, поставив на первое место модель домена, назвав ее концептуальной моделью. Оставил логическую модель и добавил еще одну связующую между ними – модель сопоставления.

Каждая модель хранится в отдельном XML – файле и является частью EDM:

  • Концептуальная модель (модель домена) – в файлах с расширением CSDL;
  • Модель хранения данных (логическая модель)– в файлах c расширением SSDL;
  • Модель сопоставления (Мэппинг) – в файлах с расширением MSL.
  • Каждый из этих файлов вы можете изменить, управляя общей моделью EDM. Изменения в концептуальной модели требуют изменений в моделях хранения и сопоставления. Последние можно изменять без необходимости менять концептуальную.

Доступ к сущностям БД

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

Следующий шаг после моделирования – это разработка кода манипуляции с сущностями в БД. Такой код разрабатывается на основе:

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

LINQ – это набор методов расширения языков .NET, позволяющий манипулировать сущностями в БД не зависящие от источника данных. Запросы LINQ транслируются деревья команд, а затем в запросы SQL, специфичные для хранилища.

Entity SQL – это обобщенный SQL, не зависимый от конкретного хранилища. Реализует более низкоуровневый подход.

Архитектура доступа к данным

Поставщик данных EntityClient – это надстройка над поставщиками конкретной БД. Он управляет запросами, переводит их в вид запросов к конкретной БД. Поставщик Entity работает с поставщиком реляционной БД через контекст обьекта.

Контекст обьекта – это класс производный от System.Data.Entity.DbContext или System.Data.Objects.ObjectContext и используется как контейнер сущностей. Он предназначен для фиксации изменений в БД, управляет распараллеливанием задач обращения к БД, через него производится вставка, обновление и удаление данных.

Как подключить к проекту

Entity – это фреймворк или сборка. Подключается к любому проекту через диспетчера пакетов NuGet. Диспетчер пакетов находится в Visual Studio в пункте меню Сервис:

  • Выберите пункт «Управление пакетами NuGet для решения»;
  • На вкладке обзор введите в поле поиска Entity (вы должны быть подключены к интернету);
  • Когда Visual Studio найдет пакет выберите его;
  • В правом внутренем окне пакетного менеджера отметьте галочкой проект, к которому нужно подцепить Entity и нажмите установить.
  • Принимайте условия лицензионного соглашения и нажимайте кнопку «принять»

Visual Studio все скачает (30МБайт) и установит и добавит необходимые ссылки в проект.

Раскрытие стратегий в Entity Framework: рабочий процесс создания модели

Посетителей: 2844 | Просмотров: 3925 (сегодня 0) Шрифт:

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

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

Три варианта создания концептуальной модели


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

  • Database First — вы начинаете с существующей базы данных и используете мастер для генерации на ее основе концептуальной модели;
  • Model First — вы начинаете с нуля. С помощью визуального дизайнера (EDM Designer) проектируется EDM, а затем на ее основе генерируется схема базы данных;
  • Code First — вы начинаете с классов, которые описывают вашу концептуальную модель. В этом случае визуальная модель отсутствует.

Database First: начинаем с существующей базы данных

На первой итерации Entity Framework у нас не было всех упомянутых вариантов. Единственный способ создания модели заключался в обратном проектировании существующей базы данных для преобразования в EDM, которое мы назвали моделированием Database First («сначала база данных») (рис. 1).

Рис. 1. При использовании Database First модель генерируется на основе существующей базы данных

На самом деле, вероятно, вы не раз видели такое. Вы открываете EDM Wizard, указываете ему существующую базу данных, выбираете, какие таблицы, представления, хранимые процедуры и пользовательские функции должны быть представлены в модели, потом щелкаете кнопку Finish. И тут же рождается модель. При подходе Database First модель начинает свою жизнь как виртуальное отражение базы данных (или ее подмножества, выбранного вами). Даже не прикладывая больше никаких усилий, разработчики все равно получат выигрыш от Entity Framework. Вы можете писать строго типизированные запросы к этой модели, и Entity Framework будет выполнять запросы за вас, материализуя строго типизированные объекты из набора результатов. Затем, когда вы работаете с результатами, Entity Framework отслеживает изменения и позволяет сохранять их в базе данных простым вызовом команды SaveChanges.

Для некоторых разработчиков больше ничего от Entity Framework и не понадобится, но в таком случае они упускают одно из самых больших преимуществ создания модели — возможность сделать ее более похожей на предметную область (классы и их связи, определенные в приложении), чем это позволяет база данных. Настройка модели — крайне важная особенность EDM, о которой не знают многие разработчики и никак ею не пользуются. Вы можете вводить в эту модель иерархии наследования, изменять структуру сущностей, объединять/разделять их и т. д.

При подходе Database First вы можете получить лучшее из двух миров: использовать существующую базу данных для очень быстрого создания модели, а затем изменять эту модель, чтобы она точнее отражала предметную область вашего приложения.

Model First: начинаем с визуальной модели

У вас не всегда будет в наличии база данных. Подход Model First позволяет проектировать модель в дизайнере и создать на основе этой модели схему вашей базы данных. Вы можете создавать свои сущности и их свойства, определять отношения и их ограничения, а также формировать иерархии наследовании прямо в дизайнере. Вы даже можете указать, какие свойства станут идентификационными ключами (identity keys) и должна ли база данных сама генерировать их значения (рис. 2).

Рис. 2. При использовании Model First вы проектируете модель, применяемую для генерации схемы базы данных

Функция Create Database from Model в EDM Designer на самом деле не создает базу данных — она генерирует SQL-код, при выполнении которого будет определена схема базы данных. Этот SQL-код имеет формат Data Definition Language (DDL).

Вы должны понимать несколько не вполне очевидных вещей. Поддержка Model First введена вVisual Studio 2010 и Microsoft .NET Framework 4. Вы не найдете Create Database в Visual Studio 2008. Кроме того, поскольку это новая функция, вам потребуется обновить используемый провайдер ADO.NET Data (например, System.Data.Sql) до версии, где эта функция уже поддерживается. Провайдер Microsoft SQL Server был обновлен при выпуске .NET 4; также были обновлены некоторые сторонние провайдеры.

Будьте готовы к тому, что в случае Model First инкрементальные обновления схемы вашей базы данных по умолчанию не осуществляются. При использовании соответствующей функции вы получите совершенно новый DDL-скрипт, который удалит и заново создаст все объекты базы данных. Модифицировать схему базы данных, не перезаписывая ее полностью, помогут внешние инструменты. В ином случае вы наверняка захотите либо заранее создавать резервную копию данных, либо написать скрипт, регенерирующий ваши тестовые данные при каждой модификации модели и повторном создании схемы базы данных.

Visual Studio предоставляет точку расширения в процессе генерации базы данных, которую можно использовать с помощью Entity Designer Database Generation Power Pack от Microsoft. Данный пакет можно скачать из Visual Studio 2010 Extension Manager или по ссылке visualstudiogallery.com. Это расширение позволяет не только вносить инкрементальные изменения в базу данных при использовании подхода Model First, но и изменять исходное сопоставление наследования Table Per Hierarchy или даже создавать собственные правила генерации DDL.

Code First: начинаем с кода и отказываемся от физической модели

При подходах Database First и Model First вы в конечном счете получаете физическое представление вашей EDM вместе с дополнительными метаданными. Исходный формат этой модели — XML. Он хранится в файле с расширением .edmx, и вы можете работать с ним в EDM Designer или как с чистым XML-кодом. В период выполнения Entity Framework считывает этот XML и создает представление модели в памяти, используя специализированные классы, представляющие метаданные — сущности, отношения и др. Исполняющая среда Entity Framework работает с этими объектами, а не с самим XML-файлом. Эти метаданные особенно важны, когда Entity Framework нужно преобразовывать запросы к модели в запросы к базе данных и получаемые наборы результатов в экземпляры сущностей, а также создавать команды базы данных для операций вставки, обновления и удаления. Visual Studio сгенерирует классы вашей предметной области из XML для последующего использования в приложении.

Мастер Йода рекомендует:  Apache все больше уступает IIS на рынке веб-серверо

TГруппа Entity Framework предложила способ создания необходимых объектов метаданных в период выполнения без физического EDMX-файла. В этом и заключается мощь третьего рабочего процесса создания модели для Entity Framework, который назвали Code First. При Code First вместо EDM вы создаете классы своей предметной области — так, как вы делали бы это в любых других .NET-разработках. В период выполнения Entity Framework будет анализировать эти классы и, используя набор соглашений по умолчанию, формировать в памяти модель, с которой сможет работать исполняющая среда Entity Framework. Поскольку ваши классы не всегда будут естественным образом предоставлять информацию, необходимую Entity Framework для создания этой модели, вы можете создать дополнительную конфигурацию (с помощью декларативных атрибутов и/или аннотаций данных либо программно с помощью текучего [fluent] API) для более детального описания модели, переопределяя упомянутые выше соглашения. Вы можете использовать конфигурацию для широкого спектра задач, связанных с моделью, — от идентификации основных ключей, не соответствующих соглашениям Code First, до тонкой настройки отношений или даже определения того, как следует представлять иерархию наследования.

Как и в Model First, в Code First по умолчанию предполагается, что у вас нет существующей базы данных, и предоставляется возможность создать базу данных на основе логически построенной модели. Но в отличие от Model First вы можете создать как файл базы данных, так и схему. В Code First у вас по-прежнему нет способа сохранить информацию базы данных, если вы модифицируете модель и заново генерируете базу данных. Однако Code First позволяет распознавать различия между моделью и базой данных, а также инициализировать базу с помощью определенных данных, используя инициализаторы базы данных.

Вы также можете использовать Code First с существующей базой данных. Если имена ваших класса и свойств не соответствуют содержимому базы данных, можно обойти эту проблему, добавив аннотации данных или конфигурацию через текучий API. На рис. 3 показан класс с атрибутами, которые заставляют Code First обеспечивать сопоставление с корректными именами таблицы и свойств, даже если имена класса и его полей не имеют точного совпадения с ними.

Рис. 3. Класс с атрибутами Code First, обеспечивающими корректное сопоставление этого класса с существующей таблицей

Дерево решений

Благодаря эволюционному развитию Entity Framework теперь поддерживает разнообразные стили разработки, но это требует от нас понимания возможных вариантов, чтобы делать правильный выбор в той или иной ситуации. Если вы предпочитаете UI для модели, используйте EDM Designer независимо от того, приступаете вы к созданию модели на основе существующей базы данных или выбираете подход Model First. Если вы делаете все программным способом и не хотите зависимости от EDMX-файла или визуального дизайнера, ваш выбор — Code First (рис. 4).

Рис. 4. Дерево решений

Prefer Visual Designer? Предпочитаете визуальный дизайнер?
Code First Code First
No Нет
Yes Да
Existing Database? Существующая база данных?
Model First Model First
Database First Database First

Заключение

Какую бы методику моделирования вы ни выбрали — Database First, Model First или Code First, после создания модели вы не заметите никакой разницы, когда начнете выдавать запросы, взаимодействовать с сущностями и сохранять их, используя исполняющую среду Entity Framework через классы модели. Кроме того, можно начать с одного рабочего процесса, а затем переключиться на другой. Вы можете создать классы Code First из EDMX с помощью шаблона DbContext Code Generation. И даже, хотя это не так-то просто, создать EDMX из классов Code First.

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

В последующих статьях мы обсудим другие важные решения, которые вам придется принимать при разработке приложений Entity Framework: выбор стратегии генерации кода для EntityObjects или POCO, способы загрузки релевантных данных (интенсивная, отложенная или явная) и написание запросов с применением LINQ to Entities или Entity SQL.

ADO.NET Entity Framework

ADO.NET Entity Framework (EF) — объектно-ориентированная технология доступа к данным, является object-relational mapping (ORM) решением для .NET Framework от Microsoft. Предоставляет возможность взаимодействия с объектами как посредством LINQ в виде LINQ to Entities, так и с использованием Entity SQL. Для облегчения построения web-решений используется как ADO.NET Data Services (Astoria), так и связка из Windows Communication Foundation и Windows Presentation Foundation, позволяющая строить многоуровневые приложения, реализуя один из шаблонов проектирования MVC, MVP или MVVM.

Содержание


История

Релиз ADO.NET Entity Framework состоялся 11 августа 2008 года в составе .NET Framework 3.5 Service Pack 1 и Visual Studio 2008 Service Pack 1. В VS 2008 вошёл EDM Wizard для реверс-инжиниринга существующих баз данных и EDM Designer для редактирования сгенерированных моделей или создания их с нуля.

23 июня 2008 года, ещё до релиза первой версии, на стадии финальной доводки Entity Framework V1, начался процесс разработки Entity Framework V2.0. [1] По словам англ. Tim Mallalieu , менеджера программы LINQ to SQL и EF, в .NET Framework 4.0 именно Entity Framework станет рекомендуемой технологией доступа к реляционным СУБД посредством LINQ. [2]

12 апреля 2010 года в составе релиза Visual Studio 2010 и .NET Framework 4.0 был представлена Entity Framework 4.0. Позже уже отдельно от фреймворка были представлены версии: 4.1 (апрель 2011), 4.2 (октябрь 2011), 4.3 (февраль 2012).

11 августа 2012 года была представлена версия 5.0.0, которая была предназначена для .NET Framework 4.5. А 17 октября 2013 года была представлена версия 6.0, которая вышла под лицензией Apache License v2, тем самым став open-source проектом.

Версия 6.0 была выпущена 17 октября 2013 года [3] и сейчас это проект с открытым исходным кодом под лицензией Apache License v2. В версии 6.0 был сделан ряд улучшений в поддержке метода работы Code First.

Entity SQL

Entity SQL представляет собой язык, подобный языку SQL, который позволяет выполнять запросы к концептуальным моделям в Entity Framework [4] .

LINQ to Entities

Это альтернативный интерфейс LINQ API, используемый для обращения к базе данных. Он отделяет сущностную объектную модель данных от физической базы данных, вводя логическое отображение между ними. Так, например, схемы реляционных баз данных не всегда подходят для построения объектно-ориентированных приложений и в результате мы имеем объектную модель приложения, существенно отличающуюся от логической модели данных, в этом случае используется LINQ to Entities, который использует модель EDM (Entity Data Model). То есть, если вам нужно ослабить связь между вашей сущностной объектной моделью данных и физической моделью данных, например, если ваши сущностные объекты конструируются из нескольких таблиц или вам нужна большая гибкость в моделировании ваших сущностных объектов используйте LINQ to Entities.

Подходы в EF

Изначально с самой первой версии Entity Framework поддерживал подход Database First, который позволял по готовой базе данных сгенерировать модель edmx. Затем эта модель использовалась для подключения к базе данных. Позже был добавлен подход Model First. Он позволял создать вручную с помощью визуального редактора модель edmx, и по ней создать базу данных. Начиная с 5.0 предпочтительным подходом становится Code First [5] . Его суть — сначала пишется код модели на C#, а затем по нему генерируется база данных. При этом модель edmx уже не используется.

Entity Framework: что это такое

Не так давно обновился Entity Framework (EF) до версии 4.1, основное нововведение, которое появилось – это Code First, подход и возможность работать с POCO объектами. Но для людей, у которых уже была готовая и спроектированная база, все равно не получалось работать с Code First, кроме того многие, имя толковых экспертов по базам данных, выбирают традиционный путь data-driven development.

Список изменений в версии 4.1 можно найти в статье — What’s New (Entity Framework 4.1), занимательно, что существует также статья — What’s Not Supported (Entity Framework 4.1)

Итак, вполне такая себе практическая задача – быстро создать слой доступа к данным (data access layer), который будет оперировать с POCO объектами, с использованием Entity Framework, отталкиваясь от уже существующей базы данных.

Многие наверное подумают, что есть смысл выбрать nHibernate или еще какие другие архитектурные решения. Но это тема других холиворов типа EF vs nHibernate, или, хорошо или плохо принимать архитектурные решения в стиле “потому-что Майкрософт”, или “потому-что не-Майкрософт”, или “потому что гладиолус”. Тут же имеем вполне практическую задачу и имеем EF.

Итак, вариант 1 — Entity Framework Power Tools

Недавно также обновилось расширение к Visual Studio 2010 – Entity Framework Power Tools. Оно еще в CTP1, но свое дело делает отлично, по крайней мере у меня нареканий не было. Расширение добавляет контекстное меню к проекту.

Конектимся к базе:

Сказать, что у вас может не возникнуть проблем с EF Power tools, – не могу. Но для того, чтобы POCO сгенерились по базе, достаточно, чтобы к проекту был подключен EF, а если точнее, сборка EntityFramework.dll версии 4.1, и аккаунт, который вы указываете на подключение к базе обладает всеми необходимыми правами, чтобы сделать свое черное дело. Как вариант EF 4.1 можно установить используя NuGet — Install-Package EntityFramework.

При соединении необходимо указывать аккаунт, который имеет доступ к БД master. Не спрашивайте почему – это требование, иначе получите ошибку в окно Output, которая отправит вас создавать такой аккаунт.

Reverse engineering нагенерит нам POCO сущностей по базе и служебные классы маппингов.

POCO классы вида:

Как видим в них ничего лишнего, разве что наличие Nullable или виртуальных свойств может выдать такой класс. Связанные таблицы реализуются как виртуальные свойства типа ICollection. Тем не менее это чистые объекты без лишних зависимостй

Маппинги придется немного подредактировать. Если у вас указывается схема БД в названии таблиц, то необходимо в классах маппингов добавить эту схему в “магических строках” вида:

В принципе с эти можно жить имея класс контекст. Но нам этого мало. Хочется иметь для этого нормальный Data access layer. А для гурманов хочется такой слой с использованием паттернов Repositorу, UnitOfWork. Чтобы не делать много рутиной работы будем использовать T4 Template.

Этот Т4 возьмем здесь — https://github.com/danemorgridge/efrepo, естественно с благодарностью автору. Нас интересует именно IRepository.tt. Он должен находится рядом с edmx файлом.

Запустим его. Получи базовые классы и реализации показанные ниже:

Базовая конкретная реализация интерфейса IRepository от этой реализации можно наследовать свои более конкретные репозитории:

Конкретная реализация интерфейса IUnitOfWork:

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


Покажу еще код использования такого слоя доступа к данным:

Вариант 2 — ADO.NET C# POCO Entity Generator

Есть и другой вариант если не гнаться за репозиториями и unit of work в своем коде. Тоже генерирует сущности. Вот только способ доступа к БД с использованием этих сущностей через класс контекст DbContext напрямую, хотя аналогичным образом можно все заврапить в репозитории. По большому счету что Entity Framework Power Tools, что ADO.NET C# POCO Entity Generator – дают нам объекты-сущности и маппинги.

А дальше можем к примеру заиспользовать Т4 скрипт из первого способа.

ADO.NET C# POCO Entity Generator находится в галереи расширений.

Также есть набор достаточно полезных ссылок, в том числе с использованием ADO.NET C# POCO Entity Generator.

Там серди них есть ссылки на то как генерить сущности с помощью ADO.NET C# POCO Entity Generator или еще один более упрощенный вариант:

Хотя лично для меня первый вариант, который я описал предпочтительнее

Как использовать POCO объекты с репозиторием или без, это уже дело техники или Т4 скрипта. Создание достойного слоя доступа к данным в Entity Framework теперь сводится к его генерации, как впрочем и в nHibernate

Что такое Entity Framework? Почему мы это используем?

Через пару дней я начну новый проект, основанный на ASP.NET MVC3 и у меня недостаточно опыта в веб-разработке.
Я просто хочу знать о Entity Framework. Что такое Entity Framework? Почему мы это используем? а также хочу знать об Object Relational Mapping . Как это связано с сущностью платформы?
Я гуглил, но не получил точное представление об этом.
Я очень хочу знать, что лежит в основе всех этих вещей?

2 ответа

Entity Framework — это объектно-реляционный картограф. Это означает, что он может возвращать данные в вашей базе данных как объект (например, объект Person со свойствами Id, Name и т. Д.) Или набор объектов.

Почему это полезно? Ну, это действительно легко. Большую часть времени вам не нужно писать какой-либо SQL самостоятельно, и итерация очень проста с использованием встроенных функций вашего языка. Когда вы вносите какие-либо изменения в объект, ORM обычно обнаруживает это и помечает объект как «измененный». Когда вы сохраняете все изменения в вашем ORM в базе данных, ORM автоматически генерирует операторы вставки / обновления / удаления на основе того, что вы сделали с объектами.

В коде вы можете работать с объектами объектно-ориентированным способом.

Однако, может быть неудобно сохранять данные в базы данных из объектов, так как вы можете в конечном итоге сопоставить свой объект со строкой запроса SQL

Инфраструктура ORM выполняет сопоставление этого объекта с SQL, генерируя операторы SQL, и Entity Manager выполнит их, когда вам нужно сохранить или загрузить объекты из базы данных. Это происходит за счет другого уровня абстракции, но это облегчит написание кода.

What is Entity Framework?

Prior to .NET 3.5, we (developers) often used to write ADO.NET code or Enterprise Data Access Block to save or retrieve application data from the underlying database. We used to open a connection to the database, create a DataSet to fetch or submit the data to the database, convert data from the DataSet to .NET objects or vice-versa to apply business rules. This was a cumbersome and error prone process. Microsoft has provided a framework called «Entity Framework» to automate all these database related activities for your application.

Entity Framework is an open-source ORM framework for .NET applications supported by Microsoft. It enables developers to work with data using objects of domain specific classes without focusing on the underlying database tables and columns where this data is stored. With the Entity Framework, developers can work at a higher level of abstraction when they deal with data, and can create and maintain data-oriented applications with less code compared with traditional applications.

Official Definition: “Entity Framework is an object-relational mapper (O/RM) that enables .NET developers to work with a database using .NET objects. It eliminates the need for most of the data-access code that developers usually need to write.”

The following figure illustrates where the Entity Framework fits into your application.

As per the above figure, Entity Framework fits between the business entities (domain classes) and the database. It saves data stored in the properties of business entities and also retrieves data from the database and converts it to business entities objects automatically.

Entity Framework Features

  • Cross-platform: EF Core is a cross-platform framework which can run on Windows, Linux and Mac.
  • Modelling: EF (Entity Framework) creates an EDM (Entity Data Model) based on POCO (Plain Old CLR Object) entities with get/set properties of different data types. It uses this model when querying or saving entity data to the underlying database.
  • Querying: EF allows us to use LINQ queries (C#/VB.NET) to retrieve data from the underlying database. The database provider will translate this LINQ queries to the database-specific query language (e.g. SQL for a relational database). EF also allows us to execute raw SQL queries directly to the database.
  • Change Tracking: EF keeps track of changes occurred to instances of your entities (Property values) which need to be submitted to the database.
  • Saving: EF executes INSERT, UPDATE, and DELETE commands to the database based on the changes occurred to your entities when you call the SaveChanges() method. EF also provides the asynchronous SaveChangesAsync() method.
  • Concurrency: EF uses Optimistic Concurrency by default to protect overwriting changes made by another user since data was fetched from the database.
  • Transactions: EF performs automatic transaction management while querying or saving data. It also provides options to customize transaction management.
  • Caching: EF includes first level of caching out of the box. So, repeated querying will return data from the cache instead of hitting the database.
  • Built-in Conventions: EF follows conventions over the configuration programming pattern, and includes a set of default rules which automatically configure the EF model.
  • Configurations: EF allows us to configure the EF model by using data annotation attributes or Fluent API to override default conventions.
  • Migrations: EF provides a set of migration commands that can be executed on the NuGet Package Manager Console or the Command Line Interface to create or manage underlying database Schema.

Entity Framework Latest Versions

Microsoft introduced Entity Framework in 2008 with .NET Framework 3.5. Since then, it released many versions of Entity Framework. Currently, there are two latest versions of Entity Framework: EF 6 and EF Core. The following table lists important difference between EF 6 and EF Core.

EF 6 Version History

EF Version Release Year .NET Framework
EF 6 2013 .NET 4.0 & .NET 4.5, VS 2012
EF 5 2012 .NET 4.0, VS 2012
EF 4.3 2011 .NET 4.0, VS 2012
EF 4.0 2010 .NET 4.0, VS 2010
EF 1.0 (or 3.5) 2008 .NET 3.5 SP1, VS 2008

Learn more about EF 6 versions history and its features here.

EF Core Version History

EF Core Version Release Date .NET Framework
EF Core 2.0 August 2020 .NET Core 2.0, VS 2020
EF Core 1.1 November 2020 .NET Core 1.1
EF Core 1.0 June 2020 .NET Core 1.0

Learn about the basic workflow while working with Entity Framework in the next chapter.

Добавить комментарий