Учебники

Entity Framework — Краткое руководство

Entity Framework — Обзор

Entity Framework был впервые выпущен в 2008 году, основным средством взаимодействия Microsoft между приложениями .NET и реляционными базами данных. Entity Framework — это Object Relational Mapper (ORM), который представляет собой тип инструмента, который упрощает сопоставление между объектами в вашем программном обеспечении и таблицами и столбцами реляционной базы данных.

  • Entity Framework (EF) — это среда ORM с открытым исходным кодом для ADO.NET, которая является частью .NET Framework.

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

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

Entity Framework (EF) — это среда ORM с открытым исходным кодом для ADO.NET, которая является частью .NET Framework.

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

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

Почему Entity Framework?

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

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

  • Если вы запрашиваете, вы можете выразить свои запросы к объектам вашего домена, используя LINQ для сущностей.

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

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

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

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

На рынке есть и другие ORM, такие как NHibernate и LLBLGen Pro. Большинство ORM обычно отображают типы доменов непосредственно в схему базы данных.

Типичный ОРМ

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

EF Метаданные времени выполнения

  • Entity Framework — это рекомендованная Microsoft технология доступа к данным для новых приложений.

  • ADO.NET, кажется, напрямую ссылается на технологию для наборов данных и таблиц данных.

  • Entity Framework — это то место, где делаются все инвестиции, продвигающиеся вперед, что имело место уже в течение ряда лет.

  • Microsoft рекомендует использовать Entity Framework поверх ADO.NET или LINQ to SQL для всех новых разработок.

Entity Framework — это рекомендованная Microsoft технология доступа к данным для новых приложений.

ADO.NET, кажется, напрямую ссылается на технологию для наборов данных и таблиц данных.

Entity Framework — это то место, где делаются все инвестиции, продвигающиеся вперед, что имело место уже в течение ряда лет.

Microsoft рекомендует использовать Entity Framework поверх ADO.NET или LINQ to SQL для всех новых разработок.

Концептуальная модель

Для разработчиков, которые привыкли к разработке, ориентированной на базы данных, самый большой сдвиг в Entity Framework заключается в том, что он позволяет вам сосредоточиться на своей бизнес-сфере. Что вы хотите, чтобы ваше приложение делало, не ограничиваясь возможностями базы данных?

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

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

  • Вы можете использовать Visual Designer для определения вашей концептуальной модели, которая затем может генерировать классы, которые вы в конечном итоге будете использовать в своем приложении.

  • Вы можете просто определить свои классы и использовать функцию Entity Framework, которая называется Code First. И тогда Entity Framework постигнет концептуальную модель.

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

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

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

Вы можете просто определить свои классы и использовать функцию Entity Framework, которая называется Code First. И тогда Entity Framework постигнет концептуальную модель.

Концептуальная модель

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

Характеристики

Ниже приведены основные функции Entity Framework. Этот список создан на основе наиболее заметных функций, а также на основе часто задаваемых вопросов о Entity Framework.

  • Entity Framework — это инструмент Microsoft.
  • Entity Framework разрабатывается как продукт с открытым исходным кодом.
  • Entity Framework больше не связан и не зависит от цикла выпуска .NET.
  • Работает с любой реляционной базой данных с действующим поставщиком Entity Framework.
  • Генерация команды SQL из LINQ для сущностей.
  • Entity Framework создаст параметризованные запросы.
  • Отслеживает изменения в объектах в памяти.
  • Позволяет вставлять, обновлять и удалять генерацию команд.
  • Работает с визуальной моделью или с вашими собственными классами.
  • Entity Framework хранит процедуру поддержки.

Entity Framework — Архитектура

Архитектура Entity Framework, снизу вверх, состоит из следующего:

Поставщики данных

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

Он переводит распространенные языки SQL, такие как LINQ, через дерево команд в собственное выражение SQL и выполняет его для конкретной системы СУБД.

Entity Client

Этот уровень выставляет уровень сущности на верхний уровень. Сущностный клиент предоставляет разработчикам возможность работать с сущностями в форме строк и столбцов, используя запросы сущностных SQL, без необходимости создавать классы для представления концептуальной схемы. Entity Client показывает уровни структуры сущности, которые являются основными функциями. Эти слои называются Entity Data Model.

Модель данных объекта

  • Уровень хранения содержит всю схему базы данных в формате XML.

  • Слой сущностей, который также является файлом XML, определяет сущности и отношения.

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

  • Службы метаданных, которые также представлены в Entity Client, предоставляют централизованный API для доступа к слоям Entity, Mapping и Storage, которые хранятся в метаданных.

Уровень хранения содержит всю схему базы данных в формате XML.

Слой сущностей, который также является файлом XML, определяет сущности и отношения.

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

Службы метаданных, которые также представлены в Entity Client, предоставляют централизованный API для доступа к слоям Entity, Mapping и Storage, которые хранятся в метаданных.

Объект Сервис

Слой Object Services — это Object Context, который представляет сеанс взаимодействия между приложениями и источником данных.

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

  • Это уровень ORM Entity Framework, который представляет результат данных для экземпляров объектов.

  • Эти сервисы позволяют разработчику использовать некоторые богатые функции ORM, такие как сопоставление первичных ключей, отслеживание изменений и т. Д., Путем написания запросов с использованием LINQ и Entity SQL.

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

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

Эти сервисы позволяют разработчику использовать некоторые богатые функции ORM, такие как сопоставление первичных ключей, отслеживание изменений и т. Д., Путем написания запросов с использованием LINQ и Entity SQL.

Entity Framework — Настройка среды

Что нового в Entity Framework 6?

Framework имеет сложный API, который позволяет вам детально контролировать все, от моделирования до поведения во время выполнения. Часть Entity Framework 5 живет внутри .NET. И другая его часть живет внутри дополнительной сборки, которая распространяется с помощью NuGet.

  • Основные функциональные возможности Entity Framework встроены в .NET Framework.

  • Поддержка Code First — вот что позволяет Entity Framework использовать классы вместо визуальной модели, а более легкий API для взаимодействия с EF находится в пакете NuGet.

  • Суть в том, что обеспечивает запросы, отслеживание изменений и все преобразования из ваших запросов в запросы SQL, а также из возврата данных в объекты.

  • Вы можете использовать пакет EF 5 NuGet как с .NET 4, так и с .NET 4.5.

  • Одна большая путаница — в .NET 4.5 добавлена ​​поддержка перечислений и пространственных данных в основные API-интерфейсы Entity Framework, что означает, что если вы используете EF 5 с .NET 4, вы не получите эти новые функции. Вы получите их только при сочетании EF5 с .NET 4.5.

Основные функциональные возможности Entity Framework встроены в .NET Framework.

Поддержка Code First — вот что позволяет Entity Framework использовать классы вместо визуальной модели, а более легкий API для взаимодействия с EF находится в пакете NuGet.

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

Вы можете использовать пакет EF 5 NuGet как с .NET 4, так и с .NET 4.5.

Одна большая путаница — в .NET 4.5 добавлена ​​поддержка перечислений и пространственных данных в основные API-интерфейсы Entity Framework, что означает, что если вы используете EF 5 с .NET 4, вы не получите эти новые функции. Вы получите их только при сочетании EF5 с .NET 4.5.

Рамочная 6

Давайте теперь посмотрим на Entity Framework 6. Основные API, которые были внутри .NET в Entity Framework 6, теперь являются частью пакета NuGet.

Entity Framework 6

Это значит —

  • Вся Entity Framework живет внутри этой сборки, которая распространяется NuGet

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

  • Вы увидите, что одной из особенностей EF6 является то, что он поддерживает перечисления и пространственные данные для .NET 4

Вся Entity Framework живет внутри этой сборки, которая распространяется NuGet

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

Вы увидите, что одной из особенностей EF6 является то, что он поддерживает перечисления и пространственные данные для .NET 4

Чтобы начать работать с Entity Framework, вам необходимо установить следующие инструменты разработки:

  • Visual Studio 2013 или выше
  • SQL Server 2012 или выше
  • Обновления Entity Framework из пакета NuGet

Microsoft предоставляет бесплатную версию Visual Studio, которая также содержит SQL Server и может быть загружена с www.visualstudio.com .

Монтаж

Шаг 1 — После завершения загрузки запустите установщик. Следующий диалог будет отображен.

Установщик Visual Studio

Шаг 2 — Нажмите на кнопку Установить, и он начнет процесс установки.

Процесс установки

Шаг 3 — После успешного завершения процесса установки вы увидите следующее диалоговое окно. Закройте это диалоговое окно и перезагрузите компьютер, если это необходимо.

Настройка завершена

Шаг 4 — Откройте Visual Studio из меню Пуск, которое откроет следующий диалог. Это будет первое время для подготовки.

Visual Studio

Шаг 5 — Как только все будет сделано, вы увидите главное окно Visual studio.

Главное окно

Давайте создадим новый проект из Файл → Новый → Проект

Новый проект

Шаг 1 — Выберите Консольное приложение и нажмите кнопку ОК.

Шаг 2 — В обозревателе решений щелкните правой кнопкой мыши свой проект.

Консольное приложение

Шаг 3 — Выберите Управление пакетами NuGet, как показано на рисунке выше, и откроется следующее окно в Visual Studio.

Visual Studio 1

Шаг 4 — Найдите Entity Framework и установите последнюю версию, нажав кнопку «Установить».

предварительный просмотр

Шаг 5 — Нажмите Ok. После завершения установки вы увидите следующее сообщение в окне вывода.

Окно вывода

Теперь вы готовы запустить приложение.

Entity Framework — Настройка базы данных

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

  • Ученик
  • Курс
  • регистрация

База данных

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

  • Отношения один-ко-многим
  • Отношения многие ко многим
  • Индивидуальные отношения

Отношения один-ко-многим

Отношения один-ко-многим являются наиболее распространенным типом отношений. В этом типе отношений строка в таблице A может иметь много совпадающих строк в таблице B, но строка в таблице B может иметь только одну совпадающую строку в таблице A. Например, на приведенной выше диаграмме в таблице Student и Enrollment есть одна -отношения ко-многим, у каждого студента может быть много зачислений, но каждый зачисление принадлежит только одному ученику.

Отношения многие ко многим

В отношении «многие ко многим» строка в таблице A может иметь много совпадающих строк в таблице B, и наоборот. Вы создаете такое отношение, определяя третью таблицу, называемую соединительной таблицей, первичный ключ которой состоит из внешних ключей как таблицы A, так и таблицы B. Например, таблица Student и Course имеет отношение «многие ко многим», которое определяется отношение «один ко многим» из каждой из этих таблиц к таблице регистрации.

Индивидуальные отношения

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

Этот тип отношений не распространен, потому что большая часть информации, относящейся таким образом, была бы таблицей «все в одном». Вы можете использовать отношения один к одному с —

  • Разделите таблицу на множество столбцов.
  • Из соображений безопасности изолируйте часть стола.
  • Храните данные, которые недолговечны и могут быть легко удалены простым удалением таблицы.
  • Хранить информацию, которая относится только к подмножеству основной таблицы.

Entity Framework — модель данных

Entity Data Model (EDM) — это расширенная версия модели Entity-Relationship, которая определяет концептуальную модель данных с использованием различных методов моделирования. Это также относится к набору понятий, которые описывают структуру данных, независимо от ее сохраненной формы.

EDM поддерживает набор примитивных типов данных, которые определяют свойства в концептуальной модели. Нам нужно рассмотреть 3 основных части, которые составляют основу Entity Framework, и вместе она называется Entity Data Model. Ниже приведены три основные части EDM.

  • Модель схемы хранения
  • Концептуальная модель
  • Картографическая модель

Модель схемы хранения

Модель хранилища, также называемая уровнем определения схемы хранилища (SSDL), представляет схематическое представление внутреннего хранилища данных.

EDM

Концептуальная модель

Концептуальная модель, также называемая слоем определения концептуальной схемы (CSDL), является моделью реальной сущности, к которой мы пишем наши запросы.

Картографическая модель

Mapping Layer — это просто отображение между концептуальной моделью и моделью хранилища.

Логическая схема и ее сопоставление с физической схемой представляется в виде EDM.

  • Visual Studio также предоставляет Entity Designer для визуального создания EDM и спецификации отображения.

  • Результатом работы инструмента является файл XML (* .edmx), определяющий схему и отображение.

  • Файл Edmx содержит артефакты метаданных Entity Framework.

Visual Studio также предоставляет Entity Designer для визуального создания EDM и спецификации отображения.

Результатом работы инструмента является файл XML (* .edmx), определяющий схему и отображение.

Файл Edmx содержит артефакты метаданных Entity Framework.

Язык определения схемы

В ADO.NET Entity Framework для определения схемы EDM используется язык определения данных на основе XML, называемый языком определения схемы (SDL).

  • SDL определяет простые типы, аналогичные другим примитивным типам, включая String, Int32, Double, Decimal и DateTime, среди прочих.

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

  • Перечисления поддерживаются только начиная с версии 5.0.

  • Сложные типы создаются из совокупности других типов. Набор свойств этих типов определяет тип сущности.

SDL определяет простые типы, аналогичные другим примитивным типам, включая String, Int32, Double, Decimal и DateTime, среди прочих.

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

Перечисления поддерживаются только начиная с версии 5.0.

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

Модель данных в основном имеет три ключевых понятия для описания структуры данных —

  • Тип объекта
  • Тип ассоциации
  • Имущество

Тип объекта

Тип сущности является фундаментальным строительным блоком для описания структуры данных в EDM.

  • В концептуальной модели типы сущностей строятся из свойств и описывают структуру понятий верхнего уровня, таких как «Студенты» и «Зачисления» в бизнес-приложении.

  • Сущность представляет определенный объект, такой как определенный студент или регистрация.

  • Каждый объект должен иметь уникальный ключ объекта в наборе объектов. Набор сущностей — это коллекция экземпляров определенного типа сущностей. Наборы объектов (и наборы ассоциаций) логически сгруппированы в контейнере объектов.

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

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

Сущность представляет определенный объект, такой как определенный студент или регистрация.

Каждый объект должен иметь уникальный ключ объекта в наборе объектов. Набор сущностей — это коллекция экземпляров определенного типа сущностей. Наборы объектов (и наборы ассоциаций) логически сгруппированы в контейнере объектов.

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

Тип объекта

Тип ассоциации

Это еще один фундаментальный строительный блок для описания отношений в EDM. В концептуальной модели связь представляет собой связь между двумя типами сущностей, такими как Студент и Зачисление.

  • Каждая ассоциация имеет два конца ассоциации, которые определяют типы объектов, участвующих в ассоциации.

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

  • Кратность окончания ассоциации может иметь значение один (1), ноль или один (0..1) или много (*).

  • К объектам на одном конце ассоциации можно получить доступ через свойства навигации или через внешние ключи, если они представлены в типе объекта.

Каждая ассоциация имеет два конца ассоциации, которые определяют типы объектов, участвующих в ассоциации.

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

Кратность окончания ассоциации может иметь значение один (1), ноль или один (0..1) или много (*).

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

Имущество

Типы сущностей содержат свойства, которые определяют их структуру и характеристики. Например, тип сущности Student может иметь такие свойства, как идентификатор ученика, имя и т. Д.

Свойство может содержать примитивные данные (например, строку, целое число или логическое значение) или структурированные данные (например, сложный тип).

Entity Framework — DbContext

Entity Framework позволяет запрашивать, вставлять, обновлять и удалять данные, используя объекты Common Language Runtime (CLR), которые называются сущностями. Entity Framework отображает сущности и отношения, которые определены в вашей модели, в базу данных. Он также предоставляет возможности для —

  • Материализация данных, возвращаемых из базы данных как объектов сущностей
  • Отслеживать изменения, которые были внесены в объекты
  • Обрабатывать параллелизм
  • Распространение изменений объекта обратно в базу данных
  • Привязать объекты к элементам управления

Основной класс, который отвечает за взаимодействие с данными как объектами, — System.Data.Entity.DbContext. API-интерфейс DbContext не выпускается как часть .NET Framework. Чтобы быть более гибкими и частыми с выпуском новых функций для Code First и DbContext API, команда Entity Framework распространяет EntityFramework.dll через функцию Microsoft NuGet.

  • NuGet позволяет добавлять ссылки на ваши проекты .NET, вытягивая соответствующие библиотеки DLL прямо в ваш проект из Интернета.

  • Расширение Visual Studio, которое называется Диспетчер пакетов библиотеки, предоставляет простой способ извлечения соответствующей сборки из Интернета в ваши проекты.

NuGet позволяет добавлять ссылки на ваши проекты .NET, вытягивая соответствующие библиотеки DLL прямо в ваш проект из Интернета.

Расширение Visual Studio, которое называется Диспетчер пакетов библиотеки, предоставляет простой способ извлечения соответствующей сборки из Интернета в ваши проекты.

DbContext

  • DbContext API в основном предназначен для упрощения вашего взаимодействия с Entity Framework.

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

  • В предыдущих версиях Entity Framework эти задачи часто было сложно обнаружить и кодировать.

  • Класс контекста управляет объектами сущностей во время выполнения, которые включают заполнение объектов данными из базы данных, отслеживание изменений и сохранение данных в базе данных.

DbContext API в основном предназначен для упрощения вашего взаимодействия с Entity Framework.

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

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

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

Определение производного класса DbContext

Рекомендуемый способ работы с контекстом — определить класс, производный от DbContext и предоставляющий свойства DbSet, которые представляют коллекции указанных объектов в контексте. Если вы работаете с EF Designer, контекст будет создан для вас. Если вы работаете с Code First, вы обычно пишете контекст самостоятельно.

Следующий код является простым примером, который показывает, что UniContext является производным от DbContext.

  • Вы можете использовать автоматические свойства с DbSet, такие как getter и setter.

  • Он также делает код намного чище, но вы не обязаны использовать его для создания DbSet, когда у вас нет другой логики для применения.

Вы можете использовать автоматические свойства с DbSet, такие как getter и setter.

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

public class UniContext : DbContext {
   public UniContext() : base("UniContext") { }
   public DbSet<Student> Students { get; set; }
   public DbSet<Enrollment> Enrollments { get; set; }
   public DbSet<Course> Courses { get; set; }
}
  • Ранее EDM использовался для генерации классов контекста, которые были получены из класса ObjectContext.

  • Работа с ObjectContext была немного сложной.

  • DbContext — это оболочка для ObjectContext, которая на самом деле похожа на ObjectContext и полезна и проста во всех моделях разработки, таких как Code First, Model First и Database First.

Ранее EDM использовался для генерации классов контекста, которые были получены из класса ObjectContext.

Работа с ObjectContext была немного сложной.

DbContext — это оболочка для ObjectContext, которая на самом деле похожа на ObjectContext и полезна и проста во всех моделях разработки, таких как Code First, Model First и Database First.

Запросы

Есть три типа запросов, которые вы можете использовать, такие как —

  • Добавление нового объекта.
  • Изменение или обновление значений свойств существующего объекта.
  • Удаление существующего объекта.

Добавление новых сущностей

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

private static void AddStudent() {

   using (var context = new UniContext()) {

      var student = new Student {
         LastName = "Khan", 
         FirstMidName = "Ali", 
         EnrollmentDate = DateTime.Parse("2005-09-01") 
      };

      context.Students.Add(student); 
      context.SaveChanges();

   }
}

Изменение существующих объектов

Изменить существующие объекты так же просто, как обновить значение, присвоенное свойству (ам), которое вы хотите изменить, и вызвать SaveChanges. В следующем коде фамилия Али была изменена с Хана на Аслам.

private static void AddStudent() {

   private static void ChangeStudent() {

      using (var context = new UniContext()) {

         var student = (from d in context.Students
            where d.FirstMidName == "Ali" select d).Single();
         student.LastName = "Aslam";
         context.SaveChanges();

      }
   }
}

Удаление существующих объектов

Чтобы удалить объект, используя Entity Framework, вы используете метод Remove в DbSet. Удалить работы как для существующих, так и для вновь добавленных объектов. Вызов Remove для объекта, который был добавлен, но еще не сохранен в базе данных, отменяет добавление объекта. Сущность удаляется из трекера изменений и больше не отслеживается DbContext. Вызов Remove для существующей сущности, которая отслеживается изменениями, зарегистрирует сущность для удаления при следующем вызове SaveChanges. В следующем примере показан случай, когда студент удаляется из базы данных, имя которой — Али.

private static void DeleteStudent() {

   using (var context = new UniContext()) {
      var bay = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
      context.Students.Remove(bay);
      context.SaveChanges();
   }
}

Entity Framework — Типы

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

  • POCO лица
  • Динамический прокси

POCO Entities

  • POCO означает «старые» объекты CLR, которые можно использовать в качестве существующих объектов домена в вашей модели данных.

  • Классы данных POCO, которые отображаются на объекты, определяются в модели данных.

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

  • Вы можете использовать шаблон POCO для генерации невосприимчивых типов сущностей из концептуальной модели.

POCO означает «старые» объекты CLR, которые можно использовать в качестве существующих объектов домена в вашей модели данных.

Классы данных POCO, которые отображаются на объекты, определяются в модели данных.

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

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

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

Концептуальная модель сущности

Чтобы сгенерировать сущности POCO для вышеуказанной модели Entity —

Шаг 1 — Щелкните правой кнопкой мыши в окне дизайнера. Появится следующий диалог.

Дизайнерское окно

Шаг 2 — Выберите пункт Добавить код генерации …

Генерация кода

Шаг 3 — Выберите EF 6.x DbContext Generator, написать имя , а затем нажмите кнопку Добавить.

В обозревателе решений вы увидите, что генерируются шаблоны POCODemo.Context.tt и POCODemo.tt.

Обозреватель решений

POCODemo.Context генерирует DbContext и наборы объектов, которые вы можете возвращать и использовать для запросов, скажем, для контекста, студентов и курсов и т. Д.

генерировать

Другой шаблон имеет дело со всеми типами Student, Courses и т. Д. Ниже приведен код для класса Student, который автоматически генерируется из Entity Model.

namespace ConsoleApplication1 {

   using System;
   using System.Collections.Generic;

   public partial class Student {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Student() {
         this.Enrollments = new HashSet<Enrollment>();
      }

      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public System.DateTime EnrollmentDate { get; set; }

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         CA2227:CollectionPropertiesShouldBeReadOnly")]

      public virtual ICollection<Enrollment> Enrollments { get; set; }

   }
}

Аналогичные классы создаются для таблиц курса и регистрации из модели сущностей.

Динамический прокси

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

  • Вы можете переопределить некоторые свойства объекта для автоматического выполнения действий при обращении к свойству.

  • Этот механизм используется для поддержки отложенной загрузки отношений и автоматического отслеживания изменений.

  • Этот метод также применим к тем моделям, которые созданы с использованием Code First и EF Designer.

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

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

Этот метод также применим к тем моделям, которые созданы с использованием Code First и EF Designer.

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

  • Пользовательский класс данных должен быть объявлен с публичным доступом.

  • Пользовательский класс данных не должен быть запечатан.

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

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

  • Используйте защищенный конструктор без параметров, если вы хотите, чтобы метод CreateObject использовался для создания прокси для объекта POCO.

  • Вызов метода CreateObject не гарантирует создание прокси-сервера: класс POCO должен соответствовать другим требованиям, описанным в этом разделе.

  • Класс не может реализовать интерфейсы IEntityWithChangeTracker или IEntityWithRelationships, потому что прокси-классы реализуют эти интерфейсы.

  • Параметр ProxyCreationEnabled должен иметь значение true.

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

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

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

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

Используйте защищенный конструктор без параметров, если вы хотите, чтобы метод CreateObject использовался для создания прокси для объекта POCO.

Вызов метода CreateObject не гарантирует создание прокси-сервера: класс POCO должен соответствовать другим требованиям, описанным в этом разделе.

Класс не может реализовать интерфейсы IEntityWithChangeTracker или IEntityWithRelationships, потому что прокси-классы реализуют эти интерфейсы.

Параметр ProxyCreationEnabled должен иметь значение true.

В следующем примере показан класс динамического прокси-объекта.

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Чтобы отключить создание прокси-объектов, установите для свойства ProxyCreationEnabled значение false.

Entity Framework — Отношения

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

  • Ученик
  • Курс
  • регистрация

Реляционная база данных

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

  • Отношения один-ко-многим
  • Отношения многие ко многим
  • Индивидуальные отношения

Отношения один-ко-многим

  • Отношения «один ко многим» являются наиболее распространенным типом отношений.

  • В этом типе отношений строка в таблице A может иметь много совпадающих строк в таблице B, но строка в таблице B может иметь только одну соответствующую строку в таблице A.

  • Внешний ключ определен в таблице, которая представляет собой конец множества отношений.

  • Например, на приведенной выше диаграмме таблицы «Учащийся» и «Зачисление» имеют отношение «один-ко-многим», у каждого учащегося может быть много зачислений, но каждая запись принадлежит только одному учащемуся.

Отношения «один ко многим» являются наиболее распространенным типом отношений.

В этом типе отношений строка в таблице A может иметь много совпадающих строк в таблице B, но строка в таблице B может иметь только одну соответствующую строку в таблице A.

Внешний ключ определен в таблице, которая представляет собой конец множества отношений.

Например, на приведенной выше диаграмме таблицы «Учащийся» и «Зачисление» имеют отношение «один-ко-многим», у каждого учащегося может быть много зачислений, но каждая запись принадлежит только одному учащемуся.

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

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Enrollment {

   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
	
   public Grade? Grade { get; set; }
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

В приведенном выше коде вы можете видеть, что класс Student содержит коллекцию Enrollment, но класс Enrollment имеет один объект Student.

Отношения многие ко многим

В отношении «многие ко многим» строка в таблице A может иметь много совпадающих строк в таблице B, и наоборот.

  • Вы можете создать такое отношение, определив третью таблицу, называемую соединительной таблицей, первичный ключ которой состоит из внешних ключей из таблицы A и таблицы B.

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

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

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

Следующий код содержит класс Course и два вышеупомянутых класса, т. Е. Student и Enrollment .

public class Course {
   [DatabaseGenerated(DatabaseGeneratedOption.None)]
	
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; } 
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Вы можете видеть, что и класс Course, и класс Student имеют коллекции объектов Enrollment, которые устанавливают связь «многие ко многим» через класс соединения Enrollment.

Индивидуальные отношения

  • В отношении «один к одному» строка в таблице A может иметь не более одной совпадающей строки в таблице B, и наоборот.

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

  • В отношении «один к одному» первичный ключ действует дополнительно как внешний ключ, и для каждой таблицы нет отдельного столбца внешнего ключа.

В отношении «один к одному» строка в таблице A может иметь не более одной совпадающей строки в таблице B, и наоборот.

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

В отношении «один к одному» первичный ключ действует дополнительно как внешний ключ, и для каждой таблицы нет отдельного столбца внешнего ключа.

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

  • Разделите таблицу на множество столбцов.
  • Из соображений безопасности изолируйте часть стола.
  • Храните данные, которые недолговечны и могут быть легко удалены простым удалением таблицы.
  • Хранить информацию, которая относится только к подмножеству основной таблицы.

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

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
   public virtual StudentProfile StudentProfile { get; set; }
}

public class StudentProfile {

   public StudentProfile() {}
   public int ID { get; set; }
   public string Email { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Вы можете видеть, что класс сущности Student содержит свойство навигации StudentProfile, а StudentProfile содержит свойство навигации Student.

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

Entity Framework — Жизненный цикл

Продолжительность жизни

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

  • Время жизни контекста — это очень важное решение, которое мы принимаем при использовании ORM.

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

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

Время жизни контекста — это очень важное решение, которое мы принимаем при использовании ORM.

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

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

Рабочий процесс данных

Жизненный цикл сущности

Жизненный цикл сущности описывает процесс, в котором сущность создается, добавляется, изменяется, удаляется и т. Д. Сущности имеют много состояний в течение своей жизни. Прежде чем посмотреть, как получить состояние объекта, давайте посмотрим, что такое состояние объекта. Состояние является перечислением типа System.Data.EntityState, которое объявляет следующие значения:

  • Добавлено: объект помечен как добавленный.

  • Удалено: объект помечен как удаленный.

  • Изменено: объект был изменен.

  • Без изменений: объект не был изменен.

  • Отдельно: сущность не отслеживается.

Добавлено: объект помечен как добавленный.

Удалено: объект помечен как удаленный.

Изменено: объект был изменен.

Без изменений: объект не был изменен.

Отдельно: сущность не отслеживается.

Изменения состояния в жизненном цикле сущности

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

Давайте поговорим о разных состояниях.

Неизменное состояние

  • Когда объект не изменен, он привязан к контексту, но не был изменен.

  • По умолчанию объект, извлеченный из базы данных, находится в этом состоянии.

  • Когда объект присоединяется к контексту (с помощью метода Attach), он аналогичным образом находится в неизмененном состоянии.

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

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

По умолчанию объект, извлеченный из базы данных, находится в этом состоянии.

Когда объект присоединяется к контексту (с помощью метода Attach), он аналогичным образом находится в неизмененном состоянии.

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

Отдельно стоящее государство

  • Detached — это состояние по умолчанию для вновь созданной сущности, поскольку контекст не может отслеживать создание какого-либо объекта в вашем коде.

  • Это верно, даже если вы создаете экземпляр объекта внутри блока using контекста.

  • Отключено — это даже состояние объектов, извлеченных из базы данных, когда отслеживание отключено.

  • Когда объект отсоединен, он не связан с контекстом, поэтому его состояние не отслеживается.

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

  • Поскольку контекст не отслеживает его, он не имеет никакого значения для Entity Framework.

Detached — это состояние по умолчанию для вновь созданной сущности, поскольку контекст не может отслеживать создание какого-либо объекта в вашем коде.

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

Отключено — это даже состояние объектов, извлеченных из базы данных, когда отслеживание отключено.

Когда объект отсоединен, он не связан с контекстом, поэтому его состояние не отслеживается.

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

Поскольку контекст не отслеживает его, он не имеет никакого значения для Entity Framework.

Добавленное состояние

  • Когда объект находится в состоянии «Добавлен», у вас есть несколько вариантов. На самом деле, вы можете только отделить его от контекста.

  • Естественно, даже если вы изменяете какое-либо свойство, состояние остается добавленным, поскольку перемещение его в значение «Изменено», «Без изменений» или «Удалено» не имеет смысла.

  • Это новый объект, который не соответствует строке в базе данных.

  • Это фундаментальная предпосылка для нахождения в одном из этих состояний (но это правило не применяется контекстом).

Когда объект находится в состоянии «Добавлен», у вас есть несколько вариантов. На самом деле, вы можете только отделить его от контекста.

Естественно, даже если вы изменяете какое-либо свойство, состояние остается добавленным, поскольку перемещение его в значение «Изменено», «Без изменений» или «Удалено» не имеет смысла.

Это новый объект, который не соответствует строке в базе данных.

Это фундаментальная предпосылка для нахождения в одном из этих состояний (но это правило не применяется контекстом).

Добавленное состояние

Модифицированное состояние

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

  • После того, как объект входит в состояние «Изменено», он может перейти в состояние «Отсоединено» или «Удалено», но не может вернуться к состоянию «Неизменен», даже если вы вручную восстановите исходные значения.

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

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

После того, как объект входит в состояние «Изменено», он может перейти в состояние «Отсоединено» или «Удалено», но не может вернуться к состоянию «Неизменен», даже если вы вручную восстановите исходные значения.

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

Удаленное состояние

  • Сущность переходит в состояние «Удалено», поскольку она не была изменена или изменена, а затем был использован метод DeleteObject.

  • Это наиболее ограничительное состояние, потому что бессмысленно переходить из этого состояния в любое другое значение, кроме Detached.

Сущность переходит в состояние «Удалено», поскольку она не была изменена или изменена, а затем был использован метод DeleteObject.

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

Оператор using, если вы хотите, чтобы все ресурсы, которыми управляет контекст, располагались в конце блока. Когда вы используете оператор using , компилятор автоматически создает блок try / finally и вызывает dispose в блоке finally.

using (var context = new UniContext()) {

   var student = new Student {
      LastName = "Khan", 
      FirstMidName = "Ali", 
      EnrollmentDate = DateTime.Parse("2005-09-01")
   };

   context.Students.Add(student);
   context.SaveChanges();
}

При работе с длительным контекстом учитывайте следующее:

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

  • Не забудьте избавиться от контекста, когда он больше не требуется.

  • Если исключение приводит к тому, что контекст находится в неисправимом состоянии, все приложение может завершиться.

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

  • При работе с веб-приложениями используйте экземпляр контекста для каждого запроса.

  • При работе с Windows Presentation Foundation (WPF) или Windows Forms используйте экземпляр контекста для каждой формы. Это позволяет вам использовать функции отслеживания изменений, которые предоставляет контекст.

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

Не забудьте избавиться от контекста, когда он больше не требуется.

Если исключение приводит к тому, что контекст находится в неисправимом состоянии, все приложение может завершиться.

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

При работе с веб-приложениями используйте экземпляр контекста для каждого запроса.

При работе с Windows Presentation Foundation (WPF) или Windows Forms используйте экземпляр контекста для каждой формы. Это позволяет вам использовать функции отслеживания изменений, которые предоставляет контекст.

Эмпирические правила

Веб-приложения

  • В настоящее время общепринятой и лучшей практикой является то, что для веб-приложений контекст используется для каждого запроса.

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

В настоящее время общепринятой и лучшей практикой является то, что для веб-приложений контекст используется для каждого запроса.

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

Настольные приложения

  • Для настольных приложений, таких как Win Forms / WPF и т. Д., Контекст используется для каждой формы / диалога / страницы.

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

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

Для настольных приложений, таких как Win Forms / WPF и т. Д., Контекст используется для каждой формы / диалога / страницы.

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

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

Entity Framework — первый подход к коду

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

  • Код первый
  • База данных сначала
  • Модель Первая

В этой главе мы кратко опишем подход «сначала код». Некоторые разработчики предпочитают работать с конструктором в коде, в то время как другие предпочитают просто работать с их кодом. Для этих разработчиков Entity Framework имеет рабочий процесс моделирования, называемый Code First.

  • Рабочий процесс моделирования Code First нацелен на несуществующую базу данных, и Code First создаст ее.

  • Его также можно использовать, если у вас пустая база данных, а затем Code First также добавит новые таблицы.

  • Code First позволяет определить вашу модель с использованием классов C # или VB.Net.

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

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

Его также можно использовать, если у вас пустая база данных, а затем Code First также добавит новые таблицы.

Code First позволяет определить вашу модель с использованием классов C # или VB.Net.

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

Код первый подход

Почему код первый?

  • Code First действительно состоит из набора частей головоломки. Во-первых, ваши классы домена.

  • Классы домена не имеют ничего общего с Entity Framework. Они просто предметы вашего бизнеса.

  • Таким образом, Entity Framework имеет контекст, который управляет взаимодействием между этими классами и вашей базой данных.

  • Контекст не является специфичным для Code First. Это особенность Entity Framework.

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

  • Все это происходит во время выполнения. Вы никогда не увидите эту модель, она просто в памяти.

  • Code First имеет возможность использовать эту модель для создания базы данных при необходимости.

  • Он также может обновить базу данных, если модель изменится, используя функцию под названием Code First Migrations.

Code First действительно состоит из набора частей головоломки. Во-первых, ваши классы домена.

Классы домена не имеют ничего общего с Entity Framework. Они просто предметы вашего бизнеса.

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

Контекст не является специфичным для Code First. Это особенность Entity Framework.

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

Все это происходит во время выполнения. Вы никогда не увидите эту модель, она просто в памяти.

Code First имеет возможность использовать эту модель для создания базы данных при необходимости.

Он также может обновить базу данных, если модель изменится, используя функцию под названием Code First Migrations.

Entity Framework — модель первого подхода

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

  • Model First отлично подходит, когда вы начинаете новый проект, где база данных еще даже не существует.

  • Модель хранится в файле EDMX и может быть просмотрена и отредактирована в Entity Framework Designer.

  • В Model First вы определяете свою модель в конструкторе Entity Framework, затем генерируете SQL, который создает схему базы данных в соответствии с вашей моделью, а затем вы выполняете SQL для создания схемы в вашей базе данных.

  • Классы, с которыми вы взаимодействуете в вашем приложении, автоматически генерируются из файла EDMX.

Model First отлично подходит, когда вы начинаете новый проект, где база данных еще даже не существует.

Модель хранится в файле EDMX и может быть просмотрена и отредактирована в Entity Framework Designer.

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

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

Ниже приведен простой пример создания нового консольного проекта с использованием подхода Model First.

Шаг 1 — Откройте Visual Studio и выберите Файл → Создать → Проект

Консольный проект

Шаг 2. Выберите Установлено → Шаблоны → Visual C # → Windows на левой панели, а затем на средней панели выберите Консольное приложение.

Шаг 3 — Введите EFModelFirstDemo в поле Имя.

Шаг 4 — Чтобы создать модель, сначала щелкните правой кнопкой мыши ваш консольный проект в обозревателе решений и выберите Добавить → Новые элементы…

модель

Следующий диалог откроется.

Добавить новое

Шаг 5 — Выберите ADO.NET Entity Data Model из средней панели и введите имя ModelFirstDemoDB в поле Имя.

Шаг 6 — Нажмите кнопку «Добавить», которая запустит диалоговое окно «Мастер модели данных объекта».

Диалог мастера моделей

Шаг 7 — Выберите пустую модель EF Designer и нажмите кнопку «Далее». Entity Framework Designer открывается с пустой моделью. Теперь мы можем начать добавлять объекты, свойства и ассоциации в модель.

Шаг 8 — Щелкните правой кнопкой мыши на поверхности дизайна и выберите Свойства. В окне «Свойства» измените имя контейнера сущностей на ModelFirstDemoDBContext.

Поверхность дизайна

Шаг 9 — Щелкните правой кнопкой мыши на поверхности дизайна и выберите Добавить новый → Объект …

Добавить новый объект

Откроется диалоговое окно Add Entity, как показано на следующем рисунке.

Диалог сущностей

Шаг 10. Введите Student в качестве имени сущности и Student Id в качестве имени свойства и нажмите Ok.

Ученик

Шаг 11 — Щелкните правой кнопкой мыши новый объект в области дизайна и выберите «Добавить новый» → «Скалярное свойство», введите «Имя» в качестве имени свойства.

Новая сущность

Шаг 12. Введите FirstName, а затем добавьте еще два скалярных свойства, таких как LastName и EnrollmentDate.

Скалярные свойства

Шаг 13 — Добавьте еще два Entity Course и Enrollment, выполнив все шаги, упомянутые выше, а также добавьте некоторые скалярные свойства, как показано в следующих шагах.

Визуальный дизайнер

Шаг 14 — У нас есть три объекта в Visual Designer, давайте добавим некоторую связь или связь между ними.

Шаг 15 — Щелкните правой кнопкой мыши на поверхности дизайна и выберите Добавить новый → Ассоциация …

Добавить ассоциацию

Шаг 16. Сделайте один конец отношения точкой для ученика с кратностью одного, а другой конец точки для зачисления с множественностью множества.

Кратность одного

Шаг 17 — Это означает, что у ученика много зачислений, и зачисление принадлежит одному ученику.

Шаг 18 — Убедитесь, что флажок Добавить свойства внешнего ключа в объект «Отправить» установлен и нажмите кнопку ОК.

Шаг 19. Аналогичным образом добавьте еще одну связь между курсом и зачислением.

Курс и зачисление

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

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

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

Шаг 1 — Щелкните правой кнопкой мыши на области конструктора и выберите «Создать базу данных из модели».

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

Шаг 2 — Вы можете выбрать существующую базу данных или создать новое соединение, нажав на Новое соединение …

Создать базу данных

Шаг 3 — Чтобы создать новую базу данных, нажмите New Connection…

Свойства соединения

Шаг 4 — Введите имя сервера и имя базы данных.

Сервер и база данных

Шаг 5 — Нажмите Далее.

Сервер и база данных 1

Шаг 6 — Нажмите Готово. Это добавит файл * .edmx.sql в проект. Вы можете выполнить сценарии DDL в Visual Studio, открыв файл .sql, затем щелкните правой кнопкой мыши и выберите «Выполнить».

Сценарии DDL

Шаг 7 — Появится следующий диалог для подключения к базе данных.

Подключиться к базе данных

Шаг 8 — При успешном выполнении вы увидите следующее сообщение.

Успешное выполнение

Шаг 9 — Зайдите в обозреватель сервера, вы увидите, что база данных создана с тремя указанными таблицами.

База данных создана

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

Шаг 1 — Щелкните правой кнопкой мыши пустое место вашей модели в EF Designer и выберите «Добавить элемент генерации кода»…

EF Designer

Вы увидите, что откроется следующее диалоговое окно Add New Item.

Диалог Открыть

Шаг 2 — Выберите EF 6.x DbContext Generator в средней панели и введите ModelFirstDemoModel в поле Имя.

Шаг 3. В обозревателе решений вы увидите, что создаются шаблоны ModelFirstDemoModel.Context.tt и ModelFirstDemoModel.tt.

Шаблон создан

ModelFirstDemoModel.Context генерирует DbCcontext и наборы объектов, которые вы можете возвращать и использовать для запросов, скажем, для контекста, студентов и курсов и т. Д.

Другой шаблон имеет дело со всеми типами Student, Courses и т. Д. Ниже приведен класс Student, который генерируется автоматически из Entity Model.

CSharp Code

Ниже приведен код C #, в котором некоторые данные вводятся и извлекаются из базы данных.

using System;
using System.Linq;

namespace EFModelFirstDemo {

   class Program {

      static void Main(string[] args) {

         using (var db = new ModelFirstDemoDBContext()) {

            // Create and save a new Student

            Console.Write("Enter a name for a new Student: ");
            var firstName = Console.ReadLine();

            var student = new Student {
               StudentID = 1,
               FirstName = firstName
            };
				
            db.Students.Add(student);
            db.SaveChanges();
				
            var query = from b in db.Students
               orderby b.FirstName select b;

            Console.WriteLine("All student in the database:");

            foreach (var item in query) {
               Console.WriteLine(item.FirstName);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
         }
      }
   }
}

Когда приведенный выше код будет выполнен, вы получите следующий вывод:

Enter a name for a new Student:
Ali Khan
All student in the database:
Ali Khan
Press any key to exit...

Мы рекомендуем выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Первый подход к базе данных

В этой главе мы узнаем о создании модели данных сущности с подходом Database First.

  • Подход Database First предоставляет альтернативу подходам Code First и Model First модели Entity Data. Он создает коды моделей (классы, свойства, DbContext и т. Д.) Из базы данных в проекте, и эти классы становятся связующим звеном между базой данных и контроллером.

  • Первый подход к базе данных создает структуру сущности из существующей базы данных. Мы используем все другие функциональные возможности, такие как синхронизация модели / базы данных и генерация кода, так же, как мы использовали их в подходе Model First.

Подход Database First предоставляет альтернативу подходам Code First и Model First модели Entity Data. Он создает коды моделей (классы, свойства, DbContext и т. Д.) Из базы данных в проекте, и эти классы становятся связующим звеном между базой данных и контроллером.

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

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

Новый консольный проект

Шаг 1 — Давайте создадим новый консольный проект с именем DatabaseFirstDemo.

Шаг 2 — Чтобы создать модель, сначала щелкните правой кнопкой мыши ваш консольный проект в обозревателе решений и выберите Добавить → Новые элементы…

Создать модель

Шаг 3 — Выберите ADO.NET Entity Data Model из средней панели и введите имя DatabaseFirstModel в поле Имя.

Шаг 4 — Нажмите кнопку «Добавить», которая запустит диалоговое окно «Мастер модели данных объекта».

Содержание модели

Шаг 5 — Выберите EF Designer из базы данных и нажмите кнопку Далее.

Мастер Entity Model

Шаг 6 — Выберите существующую базу данных и нажмите Далее.

Существующая база данных

Шаг 7 — Выберите Entity Framework 6.x и нажмите «Далее».

Entity Framework

Шаг 8 — Выберите все таблицы Views и хранимую процедуру, которую вы хотите включить, и нажмите Finish.

Вы увидите, что модель Entity и классы POCO генерируются из базы данных.

Классы поко

Теперь давайте извлечем всех студентов из базы данных, написав следующий код в файле program.cs.

using System;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         using (var db = new UniContextEntities()) {

            var query = from b in db.Students
               orderby b.FirstMidName select b;

            Console.WriteLine("All All student in the database:");

            foreach (var item in query) {
               Console.WriteLine(item.FirstMidName +" "+ item.LastName);
            }

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
         }
      }
   }
}

Когда вышеуказанная программа будет выполнена, вы получите следующий вывод:

All student in the database:
Ali Khan
Arturo   finand
Bill Gates
Carson Alexander
Gytis Barzdukas
Laura Norman
Meredith Alonso
Nino Olivetto
Peggy Justice
Yan Li
Press any key to exit...

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

Мы рекомендуем выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Подходы DEV

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

  • Мы уже видели примеры моделирования Code First, моделирования Database First и рабочего процесса моделирования Model First.

  • Рабочие процессы Database First и Model First использовали Designer, но один начинается с базы данных, чтобы создать модель, а другой начинается с модели, чтобы создать базу данных.

Мы уже видели примеры моделирования Code First, моделирования Database First и рабочего процесса моделирования Model First.

Рабочие процессы Database First и Model First использовали Designer, но один начинается с базы данных, чтобы создать модель, а другой начинается с модели, чтобы создать базу данных.

Модель дизайнера

  • Для тех разработчиков, которые не хотят использовать Visual Designer плюс генерацию кода, Entity Framework имеет совершенно другой рабочий процесс, который называется Code First.

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

  • Также возможно начать Code First с базы данных, и это делает Code First немного противоречивым. Но есть инструмент, позволяющий вам преобразовать базу данных в классы, что является отличным способом получить преимущество в кодировании.

Для тех разработчиков, которые не хотят использовать Visual Designer плюс генерацию кода, Entity Framework имеет совершенно другой рабочий процесс, который называется Code First.

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

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

Учитывая эти параметры, давайте посмотрим на дерево решений.

  • Если вы предпочитаете работать с визуальным конструктором в сгенерированном коде, вам нужно выбрать один из рабочих процессов, в которых используется EF Designer. Если ваша база данных уже существует, то Database First — ваш путь.

  • Если вы хотите использовать Visual Designer в совершенно новом проекте без базы данных, тогда вы захотите использовать Model First.

  • Если вы просто хотите работать с кодом, а не с Дизайнером, то Code First, вероятно, для вас вместе с возможностью использования инструмента, который превращает базу данных в классы.

  • Если у вас есть существующие классы, то лучше всего использовать их с Code First.

Если вы предпочитаете работать с визуальным конструктором в сгенерированном коде, вам нужно выбрать один из рабочих процессов, в которых используется EF Designer. Если ваша база данных уже существует, то Database First — ваш путь.

Если вы хотите использовать Visual Designer в совершенно новом проекте без базы данных, тогда вы захотите использовать Model First.

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

Если у вас есть существующие классы, то лучше всего использовать их с Code First.

Entity Framework — Операции с базой данных

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

  • Два из них, Database First и Model First, зависели от конструктора Entity Framework в сочетании с генерацией кода.

  • Третий, Code First, позволяет вам пропустить визуальный дизайнер и просто написать свой собственный код.

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

Два из них, Database First и Model First, зависели от конструктора Entity Framework в сочетании с генерацией кода.

Третий, Code First, позволяет вам пропустить визуальный дизайнер и просто написать свой собственный код.

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

API-интерфейс DbContext в ваших приложениях используется в качестве моста между вашими классами и вашей базой данных. DbContext является одним из наиболее важных классов в Entity Framework.

  • Это позволяет выражать и выполнять запросы.

  • Он берет результаты запросов из базы данных и преобразует их в экземпляры классов нашей модели.

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

Это позволяет выражать и выполнять запросы.

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

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

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

Реализация класса контекста

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.Core.Objects;
using System.Linq;

namespace DatabaseFirstDemo {

   public partial class UniContextEntities : DbContext {

      public UniContextEntities(): base("name = UniContextEntities") {}

      protected override void OnModelCreating(DbModelBuilder modelBuilder) {
         throw new UnintentionalCodeFirstException();
      }

      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }
}

Реализация классов домена

Курс

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic;
	
   public partial class Course {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Course() {
         this.Enrollments = new HashSet<Enrollment>();
      }
	
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
	
      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2227:CollectionPropertiesShouldBeReadOnly")]
			
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }
}

Студенческий класс

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic; 

   public partial class Student {

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2214:DoNotCallOverridableMethodsInConstructors")]

      public Student() {
         this.Enrollments = new HashSet<Enrollment>();
      }

      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public System.DateTime EnrollmentDate { get; set; }

      [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", 
         "CA2227:CollectionPropertiesShouldBeReadOnly")]
			
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }
}

Класс зачисления

namespace DatabaseFirstDemo {

   using System;
   using System.Collections.Generic; 

   public partial class Enrollment {

      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Nullable<int> Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }
}

Создать операцию

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

class Program {

   static void Main(string[] args) {

      var newStudent = new Student();

      //set student name

      newStudent.FirstMidName = "Bill";
      newStudent.LastName = "Gates";
      newStudent.EnrollmentDate = DateTime.Parse("2015-10-21");
      newStudent.ID = 100;

      //create DBContext object

      using (var dbCtx = new UniContextEntities()) {

         //Add Student object into Students DBset
         dbCtx.Students.Add(newStudent);

         // call SaveChanges method to save student into database
         dbCtx.SaveChanges();
      }
   }
}

Операция обновления

Изменить существующие объекты так же просто, как обновить значение, присвоенное свойству (ам), которое вы хотите изменить, и вызвать SaveChanges. Например, следующий код используется для изменения фамилии Али с Хана на Аслам.

using (var context = new UniContextEntities()) {

   var student = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
   student.LastName = "Aslam";
   context.SaveChanges();
}

Удалить операцию

Чтобы удалить объект, используя Entity Framework, вы используете метод Remove в DbSet. Удалить работы как для существующих, так и для вновь добавленных объектов. Вызов Remove для объекта, который был добавлен, но еще не сохранен в базе данных, отменяет добавление объекта. Сущность удаляется из трекера изменений и больше не отслеживается DbContext. Вызов Remove для существующей сущности, которая отслеживается изменениями, зарегистрирует сущность для удаления при следующем вызове SaveChanges. В следующем примере приведен код, в котором ученик удаляется из базы данных, имя которой — Али.

using (var context = new UniContextEntities()) {
   var bay = (from d in context.Students where d.FirstMidName == "Ali" select d).Single();
   context.Students.Remove(bay);
   context.SaveChanges();
}

Операция чтения

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

using (var db = new UniContextEntities()) {

   var query = from b in db.Students orderby b.FirstMidName select b;
   Console.WriteLine("All All student in the database:");

   foreach (var item in query) {
      Console.WriteLine(item.FirstMidName +" "+ item.LastName);
   }

   Console.WriteLine("Press any key to exit...");
   Console.ReadKey();
}

Entity Framework — параллелизм

Любой разработчик доступа к данным сталкивается с трудностями, отвечая на вопрос о параллелизме данных: «Что произойдет, если несколько человек одновременно редактируют одни и те же данные?»

  • Более удачливые среди нас имеют дело с бизнес-правилами, которые говорят: «Нет проблем, последний выигрывает».

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

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

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

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

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

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

Таблица курса

Перейдите к конструктору и щелкните правой кнопкой мыши в окне дизайнера и выберите модель обновления из базы данных …

дизайнер

Вы увидите, что в Entity Course добавлен еще один столбец.

Курс Entity

Щелкните правой кнопкой мыши по вновь созданному столбцу VersionNo, выберите Properties и измените ConcurrencyMode на Fixed, как показано на следующем рисунке.

Новая созданная колонка

Если для параметра ConcurrencyMode of Course.VersionNo установлено значение Fixed, то при каждом обновлении курса команда Update будет искать его, используя свой EntityKey и свойство VersionNo.

Давайте посмотрим на простой сценарий. Два пользователя извлекают один и тот же курс в одно и то же время, и пользователь 1 меняет заголовок этого курса на Maths и сохраняет изменения перед пользователем 2. Позже, когда пользователь 2 меняет заголовок этого курса, который был получен до того, как пользователь 1 сохранит свои изменения, в этом В случае, если пользователь 2 получит исключение параллелизма «User2: Произошло исключение оптимистичного параллелизма» .

using System;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;

namespace DatabaseFirstDemo {

   class Program {

      static void Main(string[] args) {

         Course c1 = null;
         Course c2 = null;

         //User 1 gets Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c1 = context.Courses.Where(s  s.CourseID == 1).Single();
         }

         //User 2 also get the same Course

         using (var context = new UniContextEntities()) {
            context.Configuration.ProxyCreationEnabled = false;
            c2 = context.Courses.Where(s  s.CourseID == 1).Single();
         }

         //User 1 updates Course Title
         c1.Title = "Edited from user1";

         //User 2 updates Course Title
         c2.Title = "Edited from user2";

         //User 1 saves changes first

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c1).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User1: Optimistic Concurrency exception occurred");
            }
         }

         //User 2 saves changes after User 1.
         //User 2 will get concurrency exection
         //because CreateOrModifiedDate is different in the database

         using (var context = new UniContextEntities()) {

            try {
               context.Entry(c2).State = EntityState.Modified;
               context.SaveChanges();
            } catch (DbUpdateConcurrencyException ex) {
               Console.WriteLine("User2: Optimistic Concurrency exception occurred");
            }
         }
      }
   }
}

Entity Framework — Транзакция

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

  • Это все прозрачно для вас, и вам никогда не придется иметь дело с этим.

  • Эта транзакция длится достаточно долго, чтобы выполнить операцию, а затем завершается.

  • Когда вы выполняете другую такую ​​операцию, начинается новая транзакция.

Это все прозрачно для вас, и вам никогда не придется иметь дело с этим.

Эта транзакция длится достаточно долго, чтобы выполнить операцию, а затем завершается.

Когда вы выполняете другую такую ​​операцию, начинается новая транзакция.

Entity Framework 6 обеспечивает следующее:

Database.BeginTransaction ()

  • Это простой и более легкий метод в существующем DbContext для запуска и завершения транзакций для пользователей.

  • Это позволяет объединить несколько операций в одной транзакции и, следовательно, либо все они зафиксированы, либо все откатаны как одна.

  • Это также позволяет пользователю более легко указать уровень изоляции для транзакции.

Это простой и более легкий метод в существующем DbContext для запуска и завершения транзакций для пользователей.

Это позволяет объединить несколько операций в одной транзакции и, следовательно, либо все они зафиксированы, либо все откатаны как одна.

Это также позволяет пользователю более легко указать уровень изоляции для транзакции.

Database.UseTransaction ()

  • Это позволяет DbContext использовать транзакцию, которая была запущена вне Entity Framework.

Это позволяет DbContext использовать транзакцию, которая была запущена вне Entity Framework.

Давайте посмотрим на следующий пример, где несколько операций выполняются в одной транзакции. Код как —

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         using (var dbContextTransaction = context.Database.BeginTransaction()) {

            try {

               Student student = new Student() {
                  ID = 200, 
                  FirstMidName = "Ali", 
                  LastName = "Khan", 
                  EnrollmentDate = DateTime.Parse("2015-12-1")
               };

               context.Students.Add(student);

               context.Database.ExecuteSqlCommand(@"UPDATE Course SET Title = 
                  'Calculus'" + "WHERE CourseID = 1045");

               var query = context.Courses.Where(c  c.CourseID == 1045);

               foreach (var item in query) {
                  Console.WriteLine(item.CourseID.ToString()
                     + " " + item.Title + " " + item.Credits);
               }

               context.SaveChanges();
               var query1 = context.Students.Where(s  s.ID == 200);

               foreach (var item in query1) {
                  Console.WriteLine(item.ID.ToString() 
                     + " " + item.FirstMidName + " " + item.LastName);
               }

               dbContextTransaction.Commit();
            } catch (Exception) {
               dbContextTransaction.Rollback();
            }

         }
      }
   }
}
  • Для начала транзакции необходимо, чтобы открытое подключение к магазину было открыто.

  • Поэтому вызов Database.BeginTransaction () откроет соединение, если оно еще не открыто.

  • Если DbContextTransaction открыла соединение, то оно будет закрыто при вызове Dispose ().

Для начала транзакции необходимо, чтобы открытое подключение к магазину было открыто.

Поэтому вызов Database.BeginTransaction () откроет соединение, если оно еще не открыто.

Если DbContextTransaction открыла соединение, то оно будет закрыто при вызове Dispose ().

Entity Framework — Представления

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

  • Фильтровать данные базовых таблиц
  • Фильтрация данных в целях безопасности
  • Централизуйте данные, распределенные по нескольким серверам
  • Создать повторно используемый набор данных

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

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

Шаг 1 — Создайте новый проект консольного приложения.

Проект приложения

Шаг 2 — Щелкните правой кнопкой мыши проект в обозревателе решений и выберите Добавить → Новый элемент.

Project Solution Explorer

Шаг 3 — Выберите ADO.NET Entity Data Model из средней панели и введите имя ViewModel в поле Имя.

Шаг 4 — Нажмите кнопку «Добавить», которая запустит диалоговое окно «Мастер модели данных объекта».

Кнопка Добавить

Шаг 5 — Выберите EF Designer из базы данных и нажмите кнопку Далее.

Мастер Entity Model

Шаг 6 — Выберите существующую базу данных и нажмите Далее.

Существующая база данных

Шаг 7 — Выберите Entity Framework 6.x и нажмите «Далее».

Entity Framework Next

Шаг 8 — Выберите таблицы и представления из вашей базы данных и нажмите Готово.

Табличное представление

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

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

Давайте рассмотрим пример, в котором все данные извлекаются из поля зрения. Ниже приведен код —

class Program {

   static void Main(string[] args) {

      using (var db = new UniContextEntities()) {

         var query = from b in db.MyViews
            orderby b.FirstMidName select b;

         Console.WriteLine("All student in the database:");

         foreach (var item in query) {
            Console.WriteLine(item.FirstMidName + " " + item.LastName);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   }
}

Когда приведенный выше код будет выполнен, вы получите следующий вывод:

All student in the database:
Ali Khan
Arturo   finand
Bill Gates
Carson Alexander
Gytis Barzdukas
Laura Norman
Meredith Alonso
Nino Olivetto
Peggy Justice
Yan Li
Press any key to exit...

Мы рекомендуем выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Индекс

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

  • Индексирование — это новая функция в структуре сущностей, где вы можете повысить производительность своего приложения Code First, сократив время, необходимое для запроса данных из базы данных.

  • Вы можете добавить индексы в свою базу данных, используя атрибут Index , и переопределить параметры по умолчанию Unique и Clustered , чтобы получить индекс, наиболее подходящий для вашего сценария.

Индексирование — это новая функция в структуре сущностей, где вы можете повысить производительность своего приложения Code First, сократив время, необходимое для запроса данных из базы данных.

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

Давайте посмотрим на следующий код, в котором атрибут Index добавлен в класс Course для CourseID.

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   [Index]
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; }
   public byte[] VersionNo { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

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

  • Чтобы сделать индекс кластеризованным, вам нужно указать IsClustered = true.

  • Аналогично, вы также можете сделать индекс уникальным, указав IsUnique = true.

Чтобы сделать индекс кластеризованным, вам нужно указать IsClustered = true.

Аналогично, вы также можете сделать индекс уникальным, указав IsUnique = true.

Давайте посмотрим на следующий код C #, где индекс кластеризован и уникален.

public partial class Course {

   public Course() {
      this.Enrollments = new HashSet<Enrollment>();
   }

   [Index(IsClustered = true, IsUnique = true)]
   public int CourseID { get; set; }
   public string Title { get; set; }
	
   public int Credits { get; set; }
   public byte[] VersionNo { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Атрибут индекса можно использовать для создания уникального индекса в базе данных. Однако это не означает, что EF сможет рассуждать об уникальности столбца при работе со связями и т. Д. Эта функция обычно упоминается как поддержка «уникальных ограничений».

Entity Framework — Хранимые процедуры

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

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

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

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

  • В качестве альтернативы вы можете просто явно контролировать то, что выполняется в хранилище, и предпочитаете создавать хранимые процедуры.

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

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

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

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

В следующем примере создается новый проект из File → New → Project.

Процедура Новый проект

Шаг 1 — Выберите Консольное приложение из средней панели и введите StoredProceduresDemo в поле имени.

Шаг 2 — В обозревателе серверов щелкните правой кнопкой мыши свою базу данных.

Шаг 3 — Выберите New Query и введите следующий код в редакторе T-SQL, чтобы добавить новую таблицу в базу данных.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = 
   OBJECT_ID(N'[dbo].[StudentGrade]') AND type in (N'U'))

BEGIN

   CREATE TABLE [dbo].[StudentGrade](

      [EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
      [CourseID] [int] NOT NULL,
      [StudentID] [int] NOT NULL,
      [Grade] [decimal](3, 2) NULL,

      CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED (
         [EnrollmentID] ASC
      )

      WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

   ) ON [PRIMARY]

END
GO

Шаг 4 — Щелкните правой кнопкой мыши на редакторе и выберите «Выполнить».

редактор

Шаг 5 — Щелкните правой кнопкой мыши по вашей базе данных и нажмите Обновить. Вы увидите новую добавленную таблицу в вашей базе данных.

Шаг 6 — В обозревателе серверов снова щелкните правой кнопкой мыши свою базу данных.

База данных сервера

Шаг 7. Выберите New Query и введите следующий код в редакторе T-SQL, чтобы добавить хранимую процедуру в базу данных, которая будет возвращать оценки учеников.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = 
   OBJECT_ID(N'[dbo].[GetStudentGrades]') AND type in (N'P', N'PC'))

BEGIN

   EXEC dbo.sp_executesql @statement = N'
   CREATE PROCEDURE [dbo].[GetStudentGrades]
   @StudentID int
   AS
   SELECT EnrollmentID, Grade, CourseID, StudentID FROM dbo.StudentGrade 
   WHERE StudentID = @StudentID
   '
END
GO

Шаг 8 — Щелкните правой кнопкой мыши на редакторе и выберите «Выполнить».

казнить

Шаг 9 — Щелкните правой кнопкой мыши по вашей базе данных и нажмите Обновить. Вы увидите, что в вашей базе данных создана хранимая процедура.

Процедура хранения создана

Шаг 10 — Щелкните правой кнопкой мыши имя проекта в обозревателе решений и выберите Добавить → Новый элемент.

Шаг 11 — Затем выберите ADO.NET Entity Data Model на панели шаблонов.

Панель шаблонов

Шаг 12 — введите SPModel в качестве имени и нажмите кнопку «Добавить».

Шаг 13 — В диалоговом окне «Выбор содержимого модели» выберите EF designer из базы данных и нажмите «Далее».

Содержание модели

Шаг 14 — Выберите вашу базу данных и нажмите Далее.

База данных 1

Шаг 15 — В диалоговом окне «Выбор объектов базы данных» щелкните таблицы, просмотры.

Объекты базы данных

Шаг 16. Выберите функцию GetStudentGradesForCourse, расположенную в узле «Хранимые процедуры и функции», и нажмите «Готово».

Шаг 17 — Выберите «Вид» → «Другие окна» → «Обозреватель модели данных объектов», щелкните правой кнопкой мыши GetStudentGrades в разделе «Импорт функций» и выберите «Редактировать».

Entity Browser

Это произведет следующий диалог.

Диалог Entity Browser

Шаг 18 — Нажмите кнопку с зависимой фиксацией Entities и выберите StudentGrade из выпадающего списка в качестве типа возврата этой хранимой процедуры и нажмите Ok.

Давайте посмотрим на следующий код C #, в котором все оценки будут получены путем передачи идентификатора студента в качестве параметра в хранимой процедуре GetStudentGrades.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         int studentID = 22;
         var studentGrades = context.GetStudentGrades(studentID);

         foreach (var student in studentGrades) {
            Console.WriteLine("Course ID: {0}, Title: {1}, Grade: {2} ", 
               student.CourseID, student.Course.Title, student.Grade);
         }

         Console.ReadKey();

      }
   }
}

Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод:

Course ID: 4022, Title: Microeconomics, Grade: 3.00
Course ID: 4041, Title: Macroeconomics, Grade: 3.50

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — отключенные объекты

В этой главе давайте рассмотрим, как вносить изменения в сущности, которые не отслеживаются контекстом. Объекты, которые не отслеживаются контекстом, называются «отключенными» объектами.

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

  • Операции над отключенными объектами гораздо чаще встречаются в приложениях N-уровня.

  • Приложения N-уровня включают получение некоторых данных на сервере и их передачу по сети на клиентский компьютер.

  • Затем клиентское приложение манипулирует этими данными, прежде чем вернуть их на сервер для сохранения.

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

Операции над отключенными объектами гораздо чаще встречаются в приложениях N-уровня.

Приложения N-уровня включают получение некоторых данных на сервере и их передачу по сети на клиентский компьютер.

Затем клиентское приложение манипулирует этими данными, прежде чем вернуть их на сервер для сохранения.

Ниже приведены два шага, которые необходимо выполнить с графом отключенного объекта или даже с одним отключенным объектом.

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

  • Установите соответствующие EntityStates для этих объектов вручную.

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

Установите соответствующие EntityStates для этих объектов вручную.

Изменить на сущность

Давайте посмотрим на следующий код, в котором сущность Student добавляется с двумя сущностями Enrollment.

class Program {

   static void Main(string[] args) {

      var student = new Student {

         ID = 1001,
         FirstMidName = "Wasim",
         LastName = "Akram", 

         EnrollmentDate = DateTime.Parse("2015-10-10"), 
            Enrollments = new List<Enrollment> {

               new Enrollment{EnrollmentID = 2001,CourseID = 4022, StudentID = 1001 },
               new Enrollment{EnrollmentID = 2002,CourseID = 4025, StudentID = 1001 },
         }
      };

      using (var context = new UniContextEntities()) {

         context.Students.Add(student);
         Console.WriteLine("New Student ({0} {1}): {2}", 
            student.FirstMidName, student.LastName, context.Entry(student).State);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0} State: {1}", 
               enrollment.EnrollmentID, context.Entry(enrollment).State);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   } 
}
  • Код создает новый экземпляр Student, который также ссылается на два новых экземпляра Enrollment в своем свойстве Enrollments.

  • Затем новый студент добавляется в контекст с помощью метода Add.

  • После добавления ученика код использует метод DbContext.Entry, чтобы получить доступ к информации об отслеживании изменений, которую Entity Framework имеет о новом ученике.

  • Из этой информации отслеживания изменений свойство State используется для записи текущего состояния объекта.

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

Код создает новый экземпляр Student, который также ссылается на два новых экземпляра Enrollment в своем свойстве Enrollments.

Затем новый студент добавляется в контекст с помощью метода Add.

После добавления ученика код использует метод DbContext.Entry, чтобы получить доступ к информации об отслеживании изменений, которую Entity Framework имеет о новом ученике.

Из этой информации отслеживания изменений свойство State используется для записи текущего состояния объекта.

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

New Student   (Wasim  Akram): Added
Enrollment ID: 2001 State: Added
Enrollment ID: 2002 State: Added
Press any key to exit...

В то время как DbSet.Add используется, чтобы сообщать Entity Framework о новых сущностях, DbSet.Attach используется, чтобы сообщать Entity Framework о существующих сущностях. Метод Attach помечает объект в неизмененном состоянии.

Давайте посмотрим на следующий код C #, в котором отключенный объект связан с DbContext.

class Program {

   static void Main(string[] args) {

      var student = new Student {

         ID = 1001,
         FirstMidName = "Wasim",
         LastName = "Akram",
         EnrollmentDate = DateTime.Parse("2015-10-10"), 

         Enrollments = new List<Enrollment> {
            new Enrollment { EnrollmentID = 2001, CourseID = 4022, StudentID = 1001 },
            new Enrollment { EnrollmentID = 2002, CourseID = 4025, StudentID = 1001 },
         }
			
      };

      using (var context = new UniContextEntities()) {

         context.Students.Attach(student);
         Console.WriteLine("New Student ({0} {1}): {2}", 
            student.FirstMidName, student.LastName, context.Entry(student).State);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0} State: {1}", enrollment.EnrollmentID, 
               context.Entry(enrollment).State);
         }

         Console.WriteLine("Press any key to exit...");
         Console.ReadKey();
      }
   }
}

Когда приведенный выше код выполняется с помощью метода Attach (), вы получите следующий вывод.

New Student   (Wasim  Akram): Unchanged
Enrollment ID: 2001 State: Unchanged
Enrollment ID: 2002 State: Unchanged
Press any key to exit...

Entity Framework — Табличная функция

В этой главе мы узнаем, как отображать табличные функции (TVF) с помощью Entity Framework Designer и как вызывать TVF из запроса LINQ.

  • TVF в настоящее время поддерживаются только в рабочем процессе Database First.

  • Впервые он был представлен в Entity Framework версии 5.

  • Чтобы использовать TVF, вы должны ориентироваться на .NET Framework 4.5 или выше.

  • Это очень похоже на хранимые процедуры, но с одним ключевым отличием, т. Е. Результат TVF является составным. Это означает, что результаты из TVF могут использоваться в запросе LINQ, а результаты хранимой процедуры — нет.

TVF в настоящее время поддерживаются только в рабочем процессе Database First.

Впервые он был представлен в Entity Framework версии 5.

Чтобы использовать TVF, вы должны ориентироваться на .NET Framework 4.5 или выше.

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

Давайте рассмотрим следующий пример создания нового проекта из File → New → Project.

Создать проект

Шаг 1 — Выберите Консольное приложение из средней панели и введите TableValuedFunctionDemo в поле имени.

Шаг 2 — В обозревателе серверов щелкните правой кнопкой мыши свою базу данных.

База данных Explorer

Шаг 3 — Выберите New Query и введите следующий код в редакторе T-SQL, чтобы добавить новую таблицу в базу данных.

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id =
   OBJECT_ID(N'[dbo].[StudentGrade]') AND type in (N'U'))

BEGIN

   CREATE TABLE [dbo].[StudentGrade](

      [EnrollmentID] [int] IDENTITY(1,1) NOT NULL,
      [CourseID] [int] NOT NULL,
      [StudentID] [int] NOT NULL,
      [Grade] [decimal](3, 2) NULL,

      CONSTRAINT [PK_StudentGrade] PRIMARY KEY CLUSTERED ([EnrollmentID] ASC)

      WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]

   ) ON [PRIMARY]

END
GO

Шаг 4 — Щелкните правой кнопкой мыши на редакторе и выберите «Выполнить».

Выберите Выполнить

Шаг 5 — Щелкните правой кнопкой мыши по вашей базе данных и нажмите Обновить. Вы увидите новую добавленную таблицу в вашей базе данных.

Добавленная таблица

Шаг 6 — Теперь создайте функцию, которая будет возвращать оценки студентов за курс. Введите следующий код в редакторе T-SQL.

CREATE FUNCTION [dbo].[GetStudentGradesForCourse]

(@CourseID INT)

RETURNS TABLE

RETURN
   SELECT [EnrollmentID],
      [CourseID],
      [StudentID],
      [Grade]
   FROM   [dbo].[StudentGrade]
   WHERE  CourseID = @CourseID 

Шаг 7 — Щелкните правой кнопкой мыши на редакторе и выберите «Выполнить».

Выбор редактора

Теперь вы можете видеть, что функция создана.

Функция создана

Шаг 8 — Щелкните правой кнопкой мыши имя проекта в обозревателе решений и выберите Добавить → Новый элемент.

Шаг 9 — Затем выберите ADO.NET Entity Data Model на панели шаблонов.

Панель шаблонов сущностей

Шаг 10 — введите TVFModel в качестве имени и нажмите кнопку «Добавить».

Шаг 11 — В диалоговом окне «Выбор содержимого модели» выберите EF designer из базы данных и нажмите «Далее».

Диалоговое окно контента

Шаг 12 — Выберите вашу базу данных и нажмите Далее.

Выберите базу данных

Шаг 13 — В диалоговом окне «Выбор объектов базы данных» выберите таблицы, представления.

Диалоговое окно объекта

Шаг 14 — Выберите функцию GetStudentGradesForCourse, расположенную в узле «Хранимые процедуры и функции», и нажмите «Готово».

Шаг 15 — Выберите «Вид» → «Другие окна» → «Браузер модели данных объектов» и щелкните правой кнопкой мыши GetStudentGradesForCourse в разделе «Импорт функций» и выберите «Редактировать».

Выберите вид

Вы увидите следующий диалог.

диалог

Шаг 16. Нажмите переключатель «Сущности», выберите «Регистрация» в поле со списком в качестве типа возврата этой функции и нажмите «ОК».

Давайте посмотрим на следующий код C #, в котором будут получены оценки всех учащихся, которые зарегистрированы в базе данных с идентификатором курса = 4022.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var CourseID = 4022;

         // Return all the best students in the Microeconomics class.
         var students = context.GetStudentGradesForCourse(CourseID);

         foreach (var result in students) {
            Console.WriteLine("Student ID:  {0}, Grade: {1}",
               result.StudentID, result.Grade);
         }

         Console.ReadKey();
      }
   }
}

Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод:

Student ID: 1, Grade: 2
Student ID: 4, Grade: 4
Student ID: 9, Grade: 3.5

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Собственный SQL

В Entity Framework вы можете делать запросы с вашими классами сущностей, используя LINQ. Вы также можете запускать запросы, используя сырой SQL напрямую к базе данных, используя DbCOntext. Методы могут применяться в равной степени к моделям, созданным с помощью Code First и EF Designer.

SQL-запрос на существующую сущность

Метод SqlQuery в DbSet позволяет писать необработанный SQL-запрос, который будет возвращать экземпляры сущностей. Возвращенные объекты будут отслеживаться контекстом так же, как если бы они были возвращены запросом LINQ. Например —

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var students = context.Students.SqlQuery("SELECT * FROM dbo.Student").ToList();

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ",
               student.ID, name, student.EnrollmentDate.ToString());
         }

         Console.ReadKey();
      }
   }
}

Приведенный выше код извлечет всех студентов из базы данных.

SQL-запрос для не-сущностных типов

SQL-запрос, возвращающий экземпляры любого типа, включая примитивные, может быть создан с помощью метода SqlQuery в классе Database. Например —

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         var studentNames = context.Database.SqlQuery
            <string>("SELECT FirstMidName FROM dbo.Student").ToList();

         foreach (var student in studentNames) {
            Console.WriteLine("Name: {0}", student);
         }

         Console.ReadKey();
      }
   }
}

Команды SQL для базы данных

Метод ExecuteSqlCommnad используется при отправке в базу данных незапрошенных команд, таких как команда «Вставить», «Обновить» или «Удалить». Давайте посмотрим на следующий код, в котором имя студента обновляется как ID = 1

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         //Update command

         int noOfRowUpdated = context.Database.ExecuteSqlCommand("Update 
            student set FirstMidName = 'Ali' where ID = 1");

         context.SaveChanges();

         var student = context.Students.SqlQuery("SELECT * FROM
            dbo.Student where ID = 1").Single();

         string name = student.FirstMidName + " " + student.LastName;

         Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ", 
            student.ID, name, student.EnrollmentDate.ToString());

         Console.ReadKey();
      }
   }
}

Приведенный выше код извлекает все имена учеников из базы данных.

Entity Framework — Поддержка Enum

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

  • Перечислимые типы имеют всевозможные преимущества при работе со свойствами, которые имеют фиксированное количество ответов.

  • Безопасность и надежность приложения повышаются при использовании перечислений.

  • Перечисление значительно усложняет пользователю ошибки, а такие проблемы, как инъекционные атаки, отсутствуют.

  • В Entity Framework перечисление может иметь следующие базовые типы:

    • Байт
    • Int16
    • Int32
    • Int64
    • SByte
  • Базовым типом элементов перечисления по умолчанию является int.

  • По умолчанию первый перечислитель имеет значение 0, а значение каждого последующего перечислителя увеличивается на 1.

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

Безопасность и надежность приложения повышаются при использовании перечислений.

Перечисление значительно усложняет пользователю ошибки, а такие проблемы, как инъекционные атаки, отсутствуют.

В Entity Framework перечисление может иметь следующие базовые типы:

Базовым типом элементов перечисления по умолчанию является int.

По умолчанию первый перечислитель имеет значение 0, а значение каждого последующего перечислителя увеличивается на 1.

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

Шаг 1 — Создать новый проект из меню Файл → Создать → Проект.

Шаг 2 — На левой панели выберите Консольное приложение.

Создание сущности

Шаг 3 — Введите EFEnumDemo в качестве имени проекта и нажмите OK.

Шаг 4 — Щелкните правой кнопкой мыши имя проекта в обозревателе решений и выберите пункт меню «Добавить» → «Новый элемент».

Шаг 5 — Выберите ADO.NET Entity Data Model на панели шаблонов.

Шаблон модели данных

Шаг 6. Введите EFEnumModel.edmx в качестве имени файла и нажмите кнопку «Добавить».

Шаг 7 — На странице мастера Entity Data Model Wizard выберите Empty EF designer Model.

Страница мастера моделей

Шаг 8 — Нажмите Готово

Шаг 9 — Затем щелкните правой кнопкой мыши в окне дизайнера и выберите Добавить → Объект.

Дизайнер Окно Entity

Откроется диалоговое окно New Entity, как показано на следующем рисунке.

Диалог нового лица

Шаг 10 — Введите Отдел в качестве имени сущности и DeptID в качестве имени свойства, оставьте тип свойства как Int32 и нажмите OK.

Шаг 11 — Щелкните правой кнопкой мыши объект и выберите Добавить новый → Скалярное свойство.

Скалярная Собственность

Шаг 12 — Переименуйте новое свойство в DeptName.

Шаг 13 — Измените тип нового свойства на Int32 (по умолчанию новое свойство имеет тип String).

Шаг 14 — Чтобы изменить тип, откройте окно «Свойства» и измените свойство «Тип» на Int32.

Тип

Шаг 15 — В Entity Framework Designer щелкните правой кнопкой мыши свойство Name, выберите Convert to enum.

Entity Framework Designer

Шаг 16. В диалоговом окне «Добавить тип перечисления» введите DepartmentNames для имени типа перечисления, измените базовый тип на Int32, а затем добавьте следующие члены к типу: физика, химия, компьютер и экономика.

Добавить Enum

Шаг 17 — Нажмите Ok.

Если вы переключитесь в окно «Обозреватель моделей», вы увидите, что тип также был добавлен в узел Enum Types.

Окно браузера модели

Давайте сгенерируем базу данных из модели, выполнив все шаги, упомянутые в главе «Подход Model First».

Шаг 1 — Щелкните правой кнопкой мыши поверхность Entity Designer и выберите «Создать базу данных из модели».

Откроется диалоговое окно «Выбор подключения к данным» мастера создания базы данных.

Шаг 2 — Нажмите кнопку «Новое соединение».

Кнопка подключения

Шаг 3 — Введите имя сервера и EnumDemo для базы данных и нажмите OK.

Шаг 4 — Появится диалоговое окно с вопросом, хотите ли вы создать новую базу данных, нажмите «Да».

Шаг 5 — Нажмите Далее, и Мастер создания базы данных создаст язык определения данных (DDL) для создания базы данных. Теперь нажмите Готово.

Шаг 6 — Щелкните правой кнопкой мыши на редакторе T-SQL и выберите «Выполнить».

TSql Editor

Шаг 7. Чтобы просмотреть сгенерированную схему, щелкните правой кнопкой мыши имя базы данных в проводнике объектов SQL Server и выберите «Обновить».

Вы увидите таблицу Отделов в базе данных.

Таблица отделов

Давайте рассмотрим следующий пример, в котором некоторые новые объекты Department добавляются в контекст и сохраняются. А потом вернуть компьютерный отдел.

class Program {

   static void Main(string[] args) {

      using (var context = new EFEnumModelContainer()) {

         context.Departments.Add(new Department { DeptName = DepartmentNames.Physics});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Computer});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Chemistry});
         context.Departments.Add(new Department { DeptName = DepartmentNames.Economics});

         context.SaveChanges();

         var department = (
            from d in context.Departments
            where d.DeptName == DepartmentNames.Computer
            select d
         ).FirstOrDefault();

         Console.WriteLine(
            "Department ID: {0}, Department Name: {1}", 
               department.DeptID, department.DeptName
         );

         Console.ReadKey();
      }
   }
}

Когда приведенный выше код будет выполнен, вы получите следующий вывод:

Department ID: 2, Department Name: Computer

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Асинхронный запрос

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

  • Entity Framework 6.0 поддерживает асинхронные операции для запроса и сохранения данных.

  • Асинхронные операции могут помочь вашему приложению следующими способами:

    • Сделайте ваше приложение более отзывчивым на взаимодействие с пользователем
    • Улучшите общую производительность вашего приложения
  • Вы можете выполнять асинхронные операции различными способами. Но ключевые слова async / await были введены в .NET Framework 4.5, что упрощает вашу работу.

  • Единственное, что вам нужно — это шаблон асинхронного ожидания / ожидания, как показано на следующем фрагменте кода.

Entity Framework 6.0 поддерживает асинхронные операции для запроса и сохранения данных.

Асинхронные операции могут помочь вашему приложению следующими способами:

Вы можете выполнять асинхронные операции различными способами. Но ключевые слова async / await были введены в .NET Framework 4.5, что упрощает вашу работу.

Единственное, что вам нужно — это шаблон асинхронного ожидания / ожидания, как показано на следующем фрагменте кода.

Давайте рассмотрим следующий пример (без использования async / await), в котором метод DatabaseOperations сохраняет нового студента в базу данных, а затем извлекает всех студентов из базы данных, и в конце на консоли выводится дополнительное сообщение.

class Program {

   static void Main(string[] args) {
      Console.WriteLine("Database Operations Started");
      DatabaseOperations();
		
      Console.WriteLine();
      Console.WriteLine("Database Operations Completed");
      Console.WriteLine();
      Console.WriteLine("Entity Framework Tutorials");
      Console.ReadKey();
   }

   public static void DatabaseOperations() {

      using (var context = new UniContextEntities()) {

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Akram", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())});

         Console.WriteLine("Calling SaveChanges.");
         context.SaveChanges();
         Console.WriteLine("SaveChanges completed.");

         // Query for all Students ordered by first name

         var students = (from s in context.Students
            orderby s.FirstMidName select s).ToList();

         // Write all students out to Console

         Console.WriteLine();
         Console.WriteLine("All Student:");

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine(" " + name);
         }
      }
   }
}

Когда приведенный выше код будет выполнен, вы получите следующий вывод:

Calling SaveChanges.
SaveChanges completed.
All Student:
Akram Khan
Ali Khan
Ali Alexander
Arturo Anand
Bill Gates
Gytis Barzdukas
Laura  Nornan
Meredith fllonso
Nino Olioetto
Peggy Justice
Yan Li

Entity Framework Tutorials

Давайте использовать новые ключевые слова async и await и внесем следующие изменения в Program.cs

  • Добавьте пространство имен System.Data.Entity, которое предоставит асинхронные методы расширения EF.

  • Добавьте пространство имен System.Threading.Tasks, которое позволит нам использовать тип задачи.

  • Обновите DatabaseOperations, чтобы пометить его как асинхронный и вернуть задачу .

  • Вызовите асинхронную версию SaveChanges и дождитесь ее завершения.

  • Вызовите асинхронную версию ToList и дождитесь результата.

Добавьте пространство имен System.Data.Entity, которое предоставит асинхронные методы расширения EF.

Добавьте пространство имен System.Threading.Tasks, которое позволит нам использовать тип задачи.

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

Вызовите асинхронную версию SaveChanges и дождитесь ее завершения.

Вызовите асинхронную версию ToList и дождитесь результата.

class Program {

   static void Main(string[] args) {
      var task = DatabaseOperations();
      Console.WriteLine();
      Console.WriteLine("Entity Framework Tutorials");
      task.Wait();
      Console.ReadKey();
   }

   public static async Task DatabaseOperations() {

      using (var context = new UniContextEntities()) {

         // Create a new blog and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())});

         Console.WriteLine("Calling SaveChanges.");
         await context.SaveChangesAsync();
         Console.WriteLine("SaveChanges completed.");

         // Query for all Students ordered by first name

         var students = await (from s in context.Students 
            orderby s.FirstMidName select s).ToListAsync();

         // Write all students out to Console

         Console.WriteLine();
         Console.WriteLine("All Student:");

         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName; 
            Console.WriteLine(" " + name);
         }
      }
   }
}

При выполнении он выдаст следующий вывод.

Calling SaveChanges.
Entity Framework Tutorials
SaveChanges completed.
All Student:
Akram Khan
Ali Khan
Ali Alexander
Arturo Anand
Bill Gates
Gytis Barzdukas
Laura  Nornan
Meredith fllonso
Nino Olioetto
Peggy Justice
Salman Khan
Yan Li

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

  • SaveChanges начинает помещать нового Студента в базу данных, а затем возвращается метод DatabaseOperations (даже если он еще не завершен), и выполнение программы в методе Main продолжается.

  • Затем сообщение записывается на консоль.

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

  • SaveChanges завершается.

  • Извлекает всех учеников из базы данных и записывает в консоль.

SaveChanges начинает помещать нового Студента в базу данных, а затем возвращается метод DatabaseOperations (даже если он еще не завершен), и выполнение программы в методе Main продолжается.

Затем сообщение записывается на консоль.

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

SaveChanges завершается.

Извлекает всех учеников из базы данных и записывает в консоль.

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Постоянство

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

Создание постоянных невежественных сущностей

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

  • В версии Entity Framework .NET 3.5, если вы хотите использовать уже существующие классы, вы должны были изменить их, заставив их наследовать от EntityObject.

  • В .NET 4 это больше не нужно. Вам не нужно изменять свои объекты, чтобы они могли участвовать в операциях Entity Framework.

  • Это позволяет нам создавать приложения, охватывающие слабую связь и разделение интересов.

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

В версии Entity Framework .NET 3.5, если вы хотите использовать уже существующие классы, вы должны были изменить их, заставив их наследовать от EntityObject.

В .NET 4 это больше не нужно. Вам не нужно изменять свои объекты, чтобы они могли участвовать в операциях Entity Framework.

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

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

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

Связанные сценарии

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

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

class Program {

   static void Main(string[] args) {

      using (var context = new MyContext()) {

         var studentList = context.Students.ToList();

         foreach (var stdnt in studentList) {
            stdnt.FirstMidName = "Edited " + stdnt.FirstMidName;
         }

         context.SaveChanges();

         //// Display all Students from the database

         var students = (from s in context.Students
            orderby s.FirstMidName select s).ToList<Student>();

         Console.WriteLine("Retrieve all Students from the database:");

         foreach (var stdnt in students) {
            string name = stdnt.FirstMidName + " " + stdnt.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
         }

         Console.ReadKey();
      }
   }
}

Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод и увидите, что отредактированное слово прикреплено перед именем, как показано в следующем выводе.

Retrieve all Students from the database: 
ID: 1, Name: Edited Edited Alain Bomer 
ID: 2, Name: Edited Edited Mark Upston 

Отключенные сценарии

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

Давайте посмотрим на следующий код, в котором новая отключенная сущность Student добавляется в контекст с помощью метода Add.

class Program {

   static void Main(string[] args) {

      var student = new Student {
         ID = 1001, 
         FirstMidName = "Wasim", 
         LastName = "Akram", 
         EnrollmentDate = DateTime.Parse( DateTime.Today.ToString())
      };

      using (var context = new MyContext()) {

         context.Students.Add(student);
         context.SaveChanges();

         //// Display all Students from the database

         var students = (from s in context.Students 
            orderby s.FirstMidName select s).ToList<Student>();

         Console.WriteLine("Retrieve all Students from the database:");

         foreach (var stdnt in students) {
            string name = stdnt.FirstMidName + " " + stdnt.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
         }

         Console.ReadKey();
      }
   }
}

Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод.

Retrieve all Students from the database:
ID: 1, Name: Edited Edited Edited Alain Bomer
ID: 2, Name: Edited Edited Edited Mark Upston
ID: 3, Name: Wasim Akram

Entity Framework — Запросы проекции

LINQ to Entities

Одним из наиболее важных понятий для понимания LINQ to Entities является то, что это декларативный язык. Основное внимание уделяется определению того, какая информация вам нужна, а не тому, как ее получить.

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

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

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

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

LINQ to Entities Основные ключевые слова

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

Старший Ключевое слово и описание
1

по возрастанию

Указывает, что операция сортировки выполняется от наименьшего (или наименьшего) элемента диапазона к наивысшему элементу диапазона. Обычно это настройка по умолчанию. Например, при выполнении алфавитной сортировки сортировка будет в диапазоне от A до Z.

2

От

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

3

нисходящий

Указывает, что операция сортировки выполняется от самого большого (или самого высокого) элемента диапазона до самого нижнего элемента диапазона. Например, при выполнении алфавитной сортировки сортировка будет в диапазоне от Z до A.

4

Равно

Используется между левым и правым предложениями оператора соединения для соединения первичного источника контекстных данных со вторичным источником контекстных данных. Поле или выражение слева от ключевого слова equals указывает первичный источник данных, а поле или выражение справа от ключевого слова equals указывает вторичный источник данных.

5

От

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

6

группа

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

7

В

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

8

В

Указывает идентификатор, который можно использовать в качестве ссылки для предложений запроса LINQ, таких как объединение, группирование и выбор.

9

Присоединиться

Создает один источник данных из двух связанных источников данных, например, в основной / подробной настройке. Объединение может указывать внутреннее, групповое или лево-внешнее объединение с внутренним объединением по умолчанию. Вы можете прочитать больше о соединениях на msdn.microsoft.com

10

Позволять

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

11

На

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

12

Сортировать по

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

13

куда

Определяет, что LINQ должен извлекать из источника данных. Вы используете одно или несколько логических выражений, чтобы определить особенности того, что извлекать. Булевы выражения отделяются друг от друга с помощью && (AND) и || (ИЛИ) операторы.

14

Выбрать

Определяет выходные данные запроса LINQ, указывая, какую информацию необходимо вернуть. Этот оператор определяет тип данных элементов, которые LINQ возвращает в процессе итерации.

по возрастанию

Указывает, что операция сортировки выполняется от наименьшего (или наименьшего) элемента диапазона к наивысшему элементу диапазона. Обычно это настройка по умолчанию. Например, при выполнении алфавитной сортировки сортировка будет в диапазоне от A до Z.

От

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

нисходящий

Указывает, что операция сортировки выполняется от самого большого (или самого высокого) элемента диапазона до самого нижнего элемента диапазона. Например, при выполнении алфавитной сортировки сортировка будет в диапазоне от Z до A.

Равно

Используется между левым и правым предложениями оператора соединения для соединения первичного источника контекстных данных со вторичным источником контекстных данных. Поле или выражение слева от ключевого слова equals указывает первичный источник данных, а поле или выражение справа от ключевого слова equals указывает вторичный источник данных.

От

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

группа

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

В

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

В

Указывает идентификатор, который можно использовать в качестве ссылки для предложений запроса LINQ, таких как объединение, группирование и выбор.

Присоединиться

Создает один источник данных из двух связанных источников данных, например, в основной / подробной настройке. Объединение может указывать внутреннее, групповое или лево-внешнее объединение с внутренним объединением по умолчанию. Вы можете прочитать больше о соединениях на msdn.microsoft.com

Позволять

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

На

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

Сортировать по

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

куда

Определяет, что LINQ должен извлекать из источника данных. Вы используете одно или несколько логических выражений, чтобы определить особенности того, что извлекать. Булевы выражения отделяются друг от друга с помощью && (AND) и || (ИЛИ) операторы.

Выбрать

Определяет выходные данные запроса LINQ, указывая, какую информацию необходимо вернуть. Этот оператор определяет тип данных элементов, которые LINQ возвращает в процессе итерации.

проекция

Проекционные запросы повышают эффективность вашего приложения, извлекая только определенные поля из вашей базы данных.

  • Если у вас есть данные, вы можете спроектировать или отфильтровать их по мере необходимости, чтобы сформировать данные перед выводом.

  • Основная задача любого выражения LINQ to Entities — получить данные и предоставить их в качестве выходных данных.

Если у вас есть данные, вы можете спроектировать или отфильтровать их по мере необходимости, чтобы сформировать данные перед выводом.

Основная задача любого выражения LINQ to Entities — получить данные и предоставить их в качестве выходных данных.

Раздел «Разработка запросов LINQ to Entities» в этой главе демонстрирует методы выполнения этой основной задачи.

Давайте посмотрим на следующий код, в котором будет получен список студентов.

using (var context = new UniContextEntities()) {

   var studentList = from s in context.Students select s;

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }
}

Один объект

Для извлечения одного объекта ученика вы можете использовать перечисляемые методы First () или FirstOrDefault, которые возвращают первый элемент последовательности. Разница между First и FirstOrDefault заключается в том, что First () сгенерирует исключение, если нет данных результата для предоставленных критериев, тогда как FirstOrDefault () возвращает значение по умолчанию null, если нет данных результата. В приведенном ниже фрагменте кода будет извлечен первый ученик из списка, чье имя Али.

using (var context = new UniContextEntities()) {

   var student = (from s in context.Students where s.FirstMidName 
      == "Ali" select s).FirstOrDefault<Student>();

   string name = student.FirstMidName + " " + student.LastName;
   Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
}

Вы также можете использовать Single () или SingleOrDefault, чтобы получить один объект ученика, который возвращает один, конкретный элемент последовательности. В следующем примере извлекается один студент, чей ID равен 2.

using (var context = new UniContextEntities()) {

   var student = (from s in context.Students where s.ID 
      == 2 select s).SingleOrDefault<Student>();
   string name = student.FirstMidName + " " + student.LastName;
	
   Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   Console.ReadKey();
}

Список объектов

Если вы хотите получить список студентов, чье имя Али — тогда, вы можете использовать перечислимый метод ToList ().

using (var context = new UniContextEntities()) {

   var studentList = (from s in context.Students where s.FirstMidName 
      == "Ali" select s).ToList();

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

порядок

Для получения данных / списка в любом конкретном порядке вы можете использовать ключевое слово orderby. В следующем коде фрагмент списка ученика будет получен в порядке возрастания.

using (var context = new UniContextEntities()) {

   var studentList = (from s in context.Students orderby
      s.FirstMidName ascending select s).ToList();

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

Стандартный Vs Projection Entity Framework Query

Предположим, у вас есть модель Student, содержащая ID, FirstMidName, LastName и EnrollmentDate. Если вы хотите вернуть список студентов, стандартный запрос вернет все поля. Но если вы хотите получить только список студентов, содержащий поля ID, FirstMidName и LastName. Здесь вы должны использовать проекционный запрос. Ниже приведен простой пример проекционного запроса.

using (var context = new UniContextEntities()) {

   var studentList = from s in context.Students
      orderby s.FirstMidName ascending
      where s.FirstMidName == "Ali"

   select new {s.ID, s.FirstMidName, s.LastName};

   foreach (var student in studentList) {
      string name = student.FirstMidName + " " + student.LastName;
      Console.WriteLine("ID : {0}, Name: {1}", student.ID, name);
   }

   Console.ReadKey();
}

Приведенный выше запрос проекции исключает поле EnrollmentDate. Это сделает ваше приложение намного быстрее.

Entity Framework — ведение журнала команд

В Entity Framework 6.0 представлена ​​новая функция, известная как Logging SQL . При работе с Entity Framework он отправляет команды или эквивалентный SQL-запрос в базу данных для выполнения операций CRUD (создание, чтение, обновление и удаление).

  • Эта особенность Entity Framework — захватывать эквивалентный SQL-запрос, сгенерированный Entity Framework, для внутреннего использования и предоставлять его в качестве вывода.

  • До Entity Framework 6 всякий раз, когда требовалась трассировка запросов и команд к базе данных, у разработчика не было выбора, кроме как использовать какую-либо стороннюю утилиту трассировки или инструмент трассировки базы данных.

  • В Entity Framework 6 эта новая функция обеспечивает простой способ регистрации всех операций, выполняемых Entity Framework.

  • Все действия, выполняемые Entity Framework, регистрируются с использованием DbContext.Database.Log.

Эта особенность Entity Framework — захватывать эквивалентный SQL-запрос, сгенерированный Entity Framework, для внутреннего использования и предоставлять его в качестве вывода.

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

В Entity Framework 6 эта новая функция обеспечивает простой способ регистрации всех операций, выполняемых Entity Framework.

Все действия, выполняемые Entity Framework, регистрируются с использованием DbContext.Database.Log.

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

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Database.Log = Console.Write;

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         context.SaveChanges();
         Console.ReadKey();
      }
   }
}

Когда приведенный выше код будет выполнен, вы получите следующий вывод, который фактически является журналом всех операций, выполненных EF в приведенном выше коде.

Opened connection at 10/28/2015 6:27:35 PM +05:00
Started transaction at 10/28/2015 6:27:35 PM +05:00
INSERT [dbo].[Student]([LastName], [FirstMidName], [EnrollmentDate])
VALUES (@0, @1, @2)
SELECT [ID]
FROM [dbo].[Student]
WHERE @@ROWCOUNT > 0 AND [ID] = scope_identity()
-- @0: 'Khan' (Type = String, Size = -1)
-- @1: 'Salman' (Type = String, Size = -1)
-- @2: '10/28/2015 12:00:00 AM' (Type = DateTime)
-- Executing at 10/28/2015 6:27:35 PM +05:00
-- Completed in 5 ms with result: SqlDataReader
Committed transaction at 10/28/2015 6:27:35 PM +05:00
Closed connection at 10/28/2015 6:27:35 PM +05:00

Когда свойство Log установлено, регистрируются следующие действия:

  • SQL для всех видов команд, например, запросов, включая вставки, обновления и удаления, созданные как часть SaveChanges

  • параметры

  • Является ли команда выполняется асинхронно

  • Отметка времени, указывающая, когда команда начала выполняться

  • Команда выполнена успешно или не выполнена

  • Некоторое указание значения результата

  • Примерное количество времени, необходимое для выполнения команды

SQL для всех видов команд, например, запросов, включая вставки, обновления и удаления, созданные как часть SaveChanges

параметры

Является ли команда выполняется асинхронно

Отметка времени, указывающая, когда команда начала выполняться

Команда выполнена успешно или не выполнена

Некоторое указание значения результата

Примерное количество времени, необходимое для выполнения команды

Вход в другое место

Если у вас уже есть какая-то структура ведения журнала, и она определяет метод ведения журнала, вы также можете записать ее в другое место.

Давайте посмотрим на следующий пример, в котором у нас есть другой класс MyLogger.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Database.Log = s  MyLogger.Log("EFLoggingDemo", s);

         // Create a new student and save it

         context.Students.Add(new Student {
            FirstMidName = "Salman", 
            LastName = "Khan", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         context.SaveChanges();
         Console.ReadKey();
      }
   }
}

public class MyLogger {

   public static void Log(string application, string message) {
      Console.WriteLine("Application: {0}, EF Message: {1} ",application, message);
   }
}

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Перехват команд

В Entity Framework 6.0 есть еще одна новая функция, известная как Перехватчик или Перехват. Код перехвата построен вокруг концепции интерфейсов перехвата . Например, интерфейс IDbCommandInterceptor определяет методы, которые вызываются до того, как EF вызовет ExecuteNonQuery, ExecuteScalar, ExecuteReader и связанные методы.

  • Entity Framework может действительно сиять, используя перехват. Используя этот подход, вы можете временно собрать гораздо больше информации без необходимости распутывать ваш код.

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

  • После создания класса, реализующего интерфейс IDbCommandInterceptor, его можно зарегистрировать в Entity Framework с помощью класса DbInterception.

  • Интерфейс IDbCommandInterceptor имеет шесть методов, и вам необходимо реализовать все эти методы. Ниже приведены основные реализации этих методов.

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

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

После создания класса, реализующего интерфейс IDbCommandInterceptor, его можно зарегистрировать в Entity Framework с помощью класса DbInterception.

Интерфейс IDbCommandInterceptor имеет шесть методов, и вам необходимо реализовать все эти методы. Ниже приведены основные реализации этих методов.

Давайте посмотрим на следующий код, в котором реализован интерфейс IDbCommandInterceptor.

public class MyCommandInterceptor : IDbCommandInterceptor {

   public static void Log(string comm, string message) {
      Console.WriteLine("Intercepted: {0}, Command Text: {1} ", comm, message);
   }

   public void NonQueryExecuted(DbCommand command, 
      DbCommandInterceptionContext<int> interceptionContext) {
         Log("NonQueryExecuted: ", command.CommandText);
   }

   public void NonQueryExecuting(DbCommand command, 
      DbCommandInterceptionContext<int> interceptionContext) {
         Log("NonQueryExecuting: ", command.CommandText);
   }

   public void ReaderExecuted(DbCommand command, 
      DbCommandInterceptionContext<DbDataReader> interceptionContext) {
         Log("ReaderExecuted: ", command.CommandText);
   }

   public void ReaderExecuting(DbCommand command, 
      DbCommandInterceptionContext<DbDataReader> interceptionContext) {
         Log("ReaderExecuting: ", command.CommandText);
   }

   public void ScalarExecuted(DbCommand command, 
      DbCommandInterceptionContext<object> interceptionContext) {
         Log("ScalarExecuted: ", command.CommandText);
   }

   public void ScalarExecuting(DbCommand command, 
      DbCommandInterceptionContext<object> interceptionContext) {
         Log("ScalarExecuting: ", command.CommandText);
   }

}

Регистрация перехватчиков

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

DbInterception.Add(new MyCommandInterceptor());

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

public class MyDBConfiguration : DbConfiguration {

   public MyDBConfiguration() {
      DbInterception.Add(new MyCommandInterceptor());
   }
}

Вы также можете настроить файл конфигурации перехватчика с помощью кода —

<entityFramework>
   <interceptors>
      <interceptor type = "EFInterceptDemo.MyCommandInterceptor, EFInterceptDemo"/>
   </interceptors>
</entityFramework>

Entity Framework — Пространственный тип данных

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

  • Entity Framework позволит новым пространственным типам данных отображаться в виде свойств в ваших классах и отображать их в пространственные столбцы в вашей базе данных.

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

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

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

Существует два основных типа пространственных данных:

  • Географический тип данных хранит эллипсоидальные данные, например, координаты широты и долготы GPS.

  • Тип данных геометрии представляет евклидову (плоскую) систему координат.

Географический тип данных хранит эллипсоидальные данные, например, координаты широты и долготы GPS.

Тип данных геометрии представляет евклидову (плоскую) систему координат.

Давайте посмотрим на следующий пример игры в крикет.

Шаг 1 — Создать новый проект из меню Файл → Создать → Проект.

Шаг 2 — На левой панели выберите Консольное приложение.

Крикетный проект

Шаг 3 — Щелкните правой кнопкой мыши на имени проекта и выберите «Управление пакетами NuGet»…

NuGet Project

Шаг 4 — Установите Entity Framework.

Шаг 5. Добавьте ссылку на сборку System.Data.Entity, а также добавьте выражение System.Data.Spatial, используя оператор для пространственных типов данных.

Добавить ссылку

Шаг 6 — Добавьте следующий класс в файл Program.cs.

public class CricketGround {
   public int ID { get; set; }
   public string Name { get; set; }
   public DbGeography Location { get; set; }
}

Шаг 7 — Помимо определения сущностей, вам нужно определить класс, который наследуется от DbContext и предоставляет свойства DbSet <TEntity>.

В Program.cs добавьте определение контекста.

public partial class CricketGroundContext : DbContext {
   public DbSet<CricketGround> CricketGrounds { get; set; }
}

Шаг 8 — Добавьте следующий код в функцию Main, которая добавит два новых объекта CricketGround в контекст.

class Program {

   static void Main(string[] args) {

      using (var context = new CricketGroundContext()) {

         context.CricketGrounds.Add(new CricketGround() {
            Name = "Shalimar Cricket Ground", 
            Location = DbGeography.FromText("POINT(-122.336106 47.605049)"), 
         });

         context.CricketGrounds.Add(new CricketGround() {
            Name = "Marghazar Stadium", Location = DbGeography
               .FromText("POINT(-122.335197 47.646711)"), 
         });

         context.SaveChanges();

         var myLocation = DbGeography.FromText("POINT(-122.296623 47.640405)");

         var cricketGround = (from cg in context.CricketGrounds
            orderby cg.Location.Distance(myLocation) select cg).FirstOrDefault();

         Console.WriteLine("The closest Cricket Ground to you is: {0}.", cricketGround.Name);
      }
   }
}

Пространственные свойства инициализируются с использованием метода DbGeography.FromText. Географическая точка, представленная как WellKnownText, передается методу, а затем сохраняет данные. После этого объект CricketGround будет извлечен там, где его местоположение находится ближе всего к указанному местоположению.

Когда приведенный выше код будет выполнен, вы получите следующий вывод:

The closest Cricket Ground to you is: Marghazar Stadium

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Наследование

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

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

Шаг 1 — Добавьте ADO.NET Entity Data Model, щелкнув правой кнопкой мыши на имени проекта и выбрав Add → New Item…

Шаг 2 — Добавьте одну сущность и назовите ее «Персона», выполнив все шаги, упомянутые в главе «Модель первый подход».

Шаг 3 — Добавьте некоторые скалярные свойства, как показано на следующем рисунке.

Добавить скалярные свойства

Шаг 4 — Мы добавим еще две сущности Ученик и Учитель , которые унаследуют свойства от Персональной таблицы.

Шаг 5 — Теперь добавьте сущность Student и выберите Person из выпадающего списка базового типа, как показано на следующем рисунке.

Базовый тип ComboBox

Шаг 6 — Аналогичным образом добавьте сущность Учитель.

Шаг 7. Теперь добавьте скалярное свойство EnrollmentDate к сущности учащегося и свойство HireDate к сущности учителя.

Дата поступления на работу

Шаг 8 — Давайте продолжим и создадим базу данных.

Шаг 9 — Щелкните правой кнопкой мыши на области дизайна и выберите «Создать базу данных из модели».

Создать базу данных

Шаг 10 — Чтобы создать новую базу данных, нажмите «Новое соединение». Откроется следующее диалоговое окно. Нажмите ОК.

Новая база данных

Шаг 11 — Нажмите Готово. Это добавит файл * .edmx.sql в проект. Вы можете выполнить сценарии DDL в Visual Studio, открыв файл .sql. Теперь щелкните правой кнопкой мыши и выберите «Выполнить».

Шаг 12 — Зайдите в обозреватель сервера и увидите, что база данных создана с тремя указанными таблицами.

База данных созданная таблица

Шаг 13 — Вы также можете видеть, что следующие классы домена также генерируются автоматически.

public partial class Person {
   public int ID { get; set; }
   public string FirstMidName { get; set; }
   public string LastName { get; set; }
}

public partial class Student : Person {
   public System.DateTime EnrollmentDate { get; set; }
}

public partial class Teacher : Person {
   public System.DateTime HireDate { get; set; }
}

Ниже приведен класс Context.

public partial class InheritanceModelContainer : DbContext {

   public InheritanceModelContainer() : 
      base("name = InheritanceModelContainer") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      throw new UnintentionalCodeFirstException();
   }

   public virtual DbSet<Person> People { get; set; }
}

Давайте добавим в базу данных некоторых учеников и учителей, а затем извлечем их из базы данных.

class Program {

   static void Main(string[] args) {

      using (var context = new InheritanceModelContainer()) {

         var student = new Student {
            FirstMidName = "Meredith", 
            LastName = "Alonso", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(student);

         var student1 = new Student {
            FirstMidName = "Arturo", 
            LastName = "Anand", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(student1);

         var techaer = new Teacher {
            FirstMidName = "Peggy", 
            LastName = "Justice", 
            HireDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(techaer);

         var techaer1 = new Teacher {
            FirstMidName = "Yan", 
            LastName = "Li", 
            HireDate = DateTime.Parse(DateTime.Today.ToString())
         };

         context.People.Add(techaer1);
         context.SaveChanges();
      }
   }
}

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

Console.WriteLine("All students in database"); 
Console.WriteLine("");

foreach (var student in context.People.OfType<Student>()) {
   string name = student.FirstMidName + " " + student.LastName;
   Console.WriteLine("ID: {0}, Name: {1}, \tEnrollment Date {2} ", 
      student.ID, name, student.EnrollmentDate.ToString());
}

Console.WriteLine("");
Console.WriteLine("************************************************************ *****");
Console.WriteLine("");
Console.WriteLine("All teachers in database");
Console.WriteLine("");

foreach (var teacher in context.People.OfType<Teacher>()) {
   string name = teacher.FirstMidName + " " + teacher.LastName;
   Console.WriteLine("ID: {0}, Name: {1}, \tHireDate {2} ", 
      teacher.ID, name, teacher.HireDate.ToString()); 
}

Console.WriteLine("");
Console.WriteLine("************************************************************ *****");
Console.ReadKey();

В первом запросе, когда вы используете OfType <Student> (), вы не сможете получить доступ к HireDate, поскольку свойство HireDate является частью сущности учителя, и аналогично свойство EnrollmentDate не будет доступно при использовании OfType <Teacher> ()

Когда приведенный выше код будет выполнен, вы получите следующий вывод:

All students in database
ID: 1, Name: Meredith Alonso,   Enrollment Date 10/30/2015 12:00:00 AM
ID: 2, Name: Arturo Anand,      Enrollment Date 10/30/2015 12:00:00 AM
*****************************************************************  
All teachers in database
ID: 3, Name: Peggy Justice,     HireDate 10/30/2015 12:00:00 AM
ID: 4, Name: Yan Li,    HireDate 10/30/2015 12:00:00 AM
*****************************************************************

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Миграция

В Entity Framework 5 и предыдущих версиях Entity Framework код был разделен между основными библиотеками (прежде всего System.Data.Entity.dll), поставляемыми как часть .NET Framework, и были распространены дополнительные библиотеки (главным образом EntityFramework.dll) и поставляется с использованием NuGet, как показано на следующей диаграмме.

DotNet Framework

В Entity Framework 6 основные API, которые ранее были частью .NET Framework, также поставляются и распространяются как часть пакета NuGet.

Основные API

Это было необходимо, чтобы позволить Entity Framework стать открытым исходным кодом. Однако, как следствие, приложения необходимо будет перестраивать всякий раз, когда возникает необходимость перенести или обновить приложение с более старых версий Entity Framework на EF 6.

Процесс миграции прост, если ваше приложение использует DbContext, который был отправлен в EF 4.1 и более поздних версиях. Но если ваше приложение — ObjectContext, тогда требуется немного больше работы.

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

Шаг 1. Первый шаг — нацеливание на .NET Framework 4.5.2 и более поздние версии. Щелкните правой кнопкой мыши свой проект и выберите свойства.

Обновление EF6

Шаг 2. Снова щелкните правой кнопкой мыши свой проект и выберите «Управление пакетами NuGet» …

Управление пакетами NuGet

Шаг 3 — На вкладке Онлайн выберите EntityFramework и нажмите Установить. Убедитесь, что ссылки на сборку System.Data.Entity.dll удалены.

При установке пакета EF6 NuGet он должен автоматически удалить любые ссылки на System.Data.Entity из вашего проекта.

Шаг 4 — Если у вас есть какая-либо модель, созданная с помощью EF Designer, вам также потребуется обновить шаблоны генерации кода для генерации кода, совместимого с EF6.

Шаг 5. В обозревателе решений в файле edmx удалите существующие шаблоны генерации кода, которые обычно называются <edmx_file_name> .tt и <edmx_file_name> .Context.tt.

EDMX

Шаг 6 — Откройте вашу модель в EF Designer, щелкните правой кнопкой мыши на области дизайна и выберите Добавить элемент генерации кода …

Шаг 7 — Добавьте соответствующий шаблон генерации кода EF 6.x.

Шаблон генерации кода

Он также автоматически сгенерирует EF6-совместимый код.

Если ваши приложения используют EF 4.1 или более позднюю версию, вам не нужно ничего менять в коде, поскольку пространства имен для типов DbContext и Code First не изменились.

Но если ваше приложение использует более старую версию Entity Framework, то такие типы, как ObjectContext, которые ранее были в System.Data.Entity.dll, были перемещены в новые пространства имен.

Шаг 8 — Вам необходимо обновить свои директивы using или Import, чтобы компилировать их в EF6.

Общее правило для изменений пространства имен заключается в том, что любой тип в System.Data. * Перемещается в System.Data.Entity.Core. *. Ниже приведены некоторые из них —

  • System.Data.EntityException ⇒ System.Data .Entity.Core. EntityException
  • System.Data.Objects.ObjectContext ⇒ System.Data .Entity.Core. Objects.ObjectContext;
  • System.Data.Objects.DataClasses.RelationshipManager ⇒ System.Data .Entity.Core. Objects.DataClasses.RelationshipManager;

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

  • System.Data.EntityState ⇒ System.Data.Entity.EntityState
  • System.Data.Objects.DataClasses.EdmFunctionAttribute ⇒ System.Data.Entity.DbFunctionAttribute

Ваш существующий проект Entity Framework будет работать в Entity Framework 6.0 без каких-либо серьезных изменений.

Entity Framework — нетерпеливая загрузка

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

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

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

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

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {
         // Load all students and related enrollments
         var students = context.Students
            .Include(s ⇒ s.Enrollments).ToList();
			
         foreach (var student in students) {
            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
				
            foreach (var enrollment in student.Enrollments) {
               Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
                  enrollment.EnrollmentID, enrollment.CourseID);
            }
         }

         Console.ReadKey();
      }
   }
}

Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод.

ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
ID: 2, Name: Meredith Alonso
       Enrollment ID: 4, Course ID: 1045
       Enrollment ID: 5, Course ID: 3141
       Enrollment ID: 6, Course ID: 2021
ID: 3, Name: Arturo Anand
       Enrollment ID: 7, Course ID: 1050
ID: 4, Name: Gytis Barzdukas
       Enrollment ID: 8, Course ID: 1050
       Enrollment ID: 9, Course ID: 4022

Ниже приведены некоторые другие формы запросов на загрузку, которые можно использовать.

// Load one Student and its related enrollments

var student1 = context.Students
   .Where(s ⇒ s.FirstMidName == "Ali")
   .Include(s ⇒ s.Enrollments).FirstOrDefault();

// Load all Students and related enrollments
// using a string to specify the relationship

var studentList = context.Students
   .Include("Enrollments").ToList();

// Load one Student and its related enrollments
// using a string to specify the relationship

var student = context.Students
   .Where(s ⇒ s.FirstMidName == "Salman")
   .Include("Enrollments").FirstOrDefault();

Несколько уровней

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

// Load all Students, all related enrollments, and all related courses

var studentList = context.Students
   .Include(s ⇒ s.Enrollments.Select(c ⇒ c.Course)).ToList();

// Load all Students, all related enrollments, and all related courses
// using a string to specify the relationships

var students = context.Students
   .Include("Enrollments.Course").ToList();

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Ленивая загрузка

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

  • При использовании типов сущностей POCO ленивая загрузка достигается созданием экземпляров производных типов прокси-серверов, а затем переопределением виртуальных свойств для добавления обработчика загрузки.

  • Ленивая загрузка по умолчанию.

  • Если вы оставите конфигурацию по умолчанию и не будете явно указывать Entity Framework в своем запросе, что вы хотите что-то кроме ленивой загрузки, то ленивая загрузка — это то, что вы получите.

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

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

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

Ленивая загрузка по умолчанию.

Если вы оставите конфигурацию по умолчанию и не будете явно указывать Entity Framework в своем запросе, что вы хотите что-то кроме ленивой загрузки, то ленивая загрузка — это то, что вы получите.

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

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

Ниже приведен класс Student, который содержит свойство навигации Enrollments.

public partial class Student {

   public Student() {
      this.Enrollments = new HashSet<Enrollment>();
   }
	
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public System.DateTime EnrollmentDate { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

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

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         //Loading students only
         IList<Student> students = context.Students.ToList<Student>();

         foreach (var student in students) {

            string name = student.FirstMidName + " " + student.LastName;
            Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
	
            foreach (var enrollment in student.Enrollments) {
               Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
                  enrollment.EnrollmentID, enrollment.CourseID);
            }
         }

         Console.ReadKey();
      }
   }
}	

Когда приведенный выше код скомпилирован и выполнен, вы получите следующий вывод.

ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
ID: 2, Name: Meredith Alonso
       Enrollment ID: 4, Course ID: 1045
       Enrollment ID: 5, Course ID: 3141
       Enrollment ID: 6, Course ID: 2021
ID: 3, Name: Arturo Anand
       Enrollment ID: 7, Course ID: 1050
ID: 4, Name: Gytis Barzdukas
       Enrollment ID: 8, Course ID: 1050
       Enrollment ID: 9, Course ID: 4022
ID: 5, Name: Yan Li
       Enrollment ID: 10, Course ID: 4041
ID: 6, Name: Peggy Justice
       Enrollment ID: 11, Course ID: 1045
ID: 7, Name: Laura Norman
       Enrollment ID: 12, Course ID: 3141

Отключить ленивую загрузку

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

Отключение для определенных свойств навигации

Ленивую загрузку коллекции Enrollments можно отключить, сделав свойство Enrollments не виртуальным, как показано в следующем примере.

public partial class Student { 

   public Student() { 
      this.Enrollments = new HashSet<Enrollment>(); 
   }
	
   public int ID { get; set; } 
   public string LastName { get; set; } 
   public string FirstMidName { get; set; } 
   public System.DateTime EnrollmentDate { get; set; }
   public ICollection<Enrollment> Enrollments { get; set; } 
}

Выключить все объекты

Ленивую загрузку можно отключить для всех объектов в контексте, установив для свойства Configuration значение false, как показано в следующем примере.

public partial class UniContextEntities : DbContext { 

   public UniContextEntities(): base("name=UniContextEntities") {
      this.Configuration.LazyLoadingEnabled = false;
   }
	
   protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
      throw new UnintentionalCodeFirstException(); 
   } 
}

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

ID: 1, Name: Ali Alexander
ID: 2, Name: Meredith Alons
ID: 3, Name: Arturo Anand
ID: 4, Name: Gytis Barzduka
ID: 5, Name: Yan Li
ID: 6, Name: Peggy Justice
ID: 7, Name: Laura Norman
ID: 8, Name: Nino Olivetto

Мы рекомендуем выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — явная загрузка

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

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

  • Для этого вы используете метод Load в записи связанной сущности.

  • Для отношения один ко многим вызовите метод Load в Collection.

  • А для отношения один-к-одному вызовите метод Load для Reference.

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

Для этого вы используете метод Load в записи связанной сущности.

Для отношения один ко многим вызовите метод Load в Collection.

А для отношения один-к-одному вызовите метод Load для Reference.

Давайте рассмотрим следующий пример, в котором отключена отложенная загрузка, а затем извлекается ученик по имени Али.

Затем информация о студентах записывается на консоли. Если вы посмотрите на код, информация о регистрации также записывается, но объект Enrollments еще не загружен, поэтому цикл foreach не будет выполнен.

После этого объект Enrollments загружается явно, теперь информация о студентах и ​​информация о регистрации будут записываться в окне консоли.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.LazyLoadingEnabled = false;

         var student = (from s in context.Students where s.FirstMidName == 
            "Ali" select s).FirstOrDefault<Student>();

         string name = student.FirstMidName + " " + student.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.WriteLine();
         Console.WriteLine("Explicitly loaded Enrollments");
         Console.WriteLine();

         context.Entry(student).Collection(s ⇒ s.Enrollments).Load();
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.ReadKey();
      }
   }
}

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

ID: 1, Name: Ali Alexander
Explicitly loaded Enrollments
ID: 1, Name: Ali Alexander
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — валидация

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

  • В Entity Framework проверка данных является частью решения для обнаружения неверных данных в приложении.

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

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

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

В Entity Framework проверка данных является частью решения для обнаружения неверных данных в приложении.

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

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

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

DbContext имеет переопределенный метод, называемый ValidateEntity. Когда вы вызываете SaveChanges, Entity Framework вызывает этот метод для каждого объекта в его кэше, состояние которого не является неизменным. Вы можете поместить логику проверки прямо здесь, как показано в следующем примере для объекта Student.

public partial class UniContextEntities : DbContext {

   protected override System.Data.Entity.Validation
      .DbEntityValidationResult ValidateEntity(DbEntityEntry entityEntry, 
      System.Collections.Generic.IDictionary<object, object> items) {

         if (entityEntry.Entity is Student) {

            if (entityEntry.CurrentValues.GetValue<string>("FirstMidName") == "") {

               var list = new List<System.Data.Entity
                  .Validation.DbValidationError>();

               list.Add(new System.Data.Entity.Validation
                  .DbValidationError("FirstMidName", "FirstMidName is required"));

               return new System.Data.Entity.Validation
                  .DbEntityValidationResult(entityEntry, list);
            }
         }

         if (entityEntry.CurrentValues.GetValue<string>("LastName") == "") {

            var list = new List<System.Data.Entity
               .Validation.DbValidationError>();

            list.Add(new System.Data.Entity.Validation
               .DbValidationError("LastName", "LastName is required"));

            return new System.Data.Entity.Validation
               .DbEntityValidationResult(entityEntry, list);
         }

         return base.ValidateEntity(entityEntry, items);
   }
}

В указанном выше методе ValidateEntity свойства Student Entity FirstMidName и LastName проверяются, если какое-либо из этих свойств имеет пустую строку, а затем возвращает сообщение об ошибке.

Давайте рассмотрим простой пример, в котором создается новый студент, но FirstMidName студента — это пустая строка, как показано в следующем коде.

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         Console.WriteLine("Adding new Student to the database");
         Console.WriteLine();

         try {

            context.Students.Add(new Student() {
               FirstMidName = "",
               LastName = "Upston"
            });

            context.SaveChanges();
         } catch (DbEntityValidationException dbValidationEx) {

            foreach (DbEntityValidationResult entityErr in 
               dbValidationEx.EntityValidationErrors) {

               foreach (DbValidationError error in entityErr.ValidationErrors) {
                  Console.WriteLine("Error: {0}",error.ErrorMessage);
               }
            }
         }

         Console.ReadKey();
      }
   }
}

Когда приведенный выше пример скомпилирован и выполнен, вы получите следующее сообщение об ошибке в окне консоли.

Adding new Student to the database  
Error: FirstMidName is required 

Мы рекомендуем выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Отслеживание изменений

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

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

  • Затем все изменения сохраняются на уровне DbContext.

  • Эти изменения дорожки теряются, если они не сохранены до уничтожения объекта DbContext.

  • Класс DbChangeTracker предоставляет вам всю информацию о текущих сущностях, отслеживаемых контекстом.

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

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

Затем все изменения сохраняются на уровне DbContext.

Эти изменения дорожки теряются, если они не сохранены до уничтожения объекта DbContext.

Класс DbChangeTracker предоставляет вам всю информацию о текущих сущностях, отслеживаемых контекстом.

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

В Entity Framework отслеживание изменений включено по умолчанию. Вы также можете отключить отслеживание изменений, установив для свойства AutoDetectChangesEnabled объекта DbContext значение false. Если для этого свойства установлено значение true, то Entity Framework поддерживает состояние объектов.

using (var context = new UniContextEntities()) {
   context.Configuration.AutoDetectChangesEnabled = true;
}

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

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.AutoDetectChangesEnabled = true;
         Console.WriteLine("Retrieve Student");

         var student = (from s in context.Students where s.FirstMidName == 
            "Ali" select s).FirstOrDefault<Student>();

         string name = student.FirstMidName + " " + student.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", student.ID, name);
         Console.WriteLine();
         Console.WriteLine("Retrieve all related enrollments");

         foreach (var enrollment in student.Enrollments) {
            Console.WriteLine("Enrollment ID: {0}, Course ID: {1}", 
               enrollment.EnrollmentID, enrollment.CourseID);
         }

         Console.WriteLine();

         Console.WriteLine("Context tracking changes of {0} entity.", 
            context.ChangeTracker.Entries().Count());

         var entries = context.ChangeTracker.Entries();

         foreach (var entry in entries) {
            Console.WriteLine("Entity Name: {0}", entry.Entity.GetType().Name);
            Console.WriteLine("Status: {0}", entry.State);
         }

         Console.ReadKey();
      }
   }
}

Когда приведенный выше пример скомпилирован и выполнен, вы получите следующий вывод.

Retrieve Student 
ID: 1, Name: Ali Alexander
Retrieve all related enrollments
       Enrollment ID: 1, Course ID: 1050
       Enrollment ID: 2, Course ID: 4022
       Enrollment ID: 3, Course ID: 4041
Context tracking changes of 4 entity.
Entity Name: Student
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged
Entity Name: Enrollment
Status: Unchanged

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

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

class Program {

   static void Main(string[] args) {

      using (var context = new UniContextEntities()) {

         context.Configuration.AutoDetectChangesEnabled = true;

         Enrollment enr = new Enrollment() { 
            StudentID = 1, CourseID = 3141 
         };

         Console.WriteLine("Adding New Enrollment");
         context.Enrollments.Add(enr);
         Console.WriteLine("Delete Student");

         var student = (from s in context.Students where s.ID == 
            23 select s).SingleOrDefault<Student>();

         context.Students.Remove(student);
         Console.WriteLine("");

         Console.WriteLine("Context tracking changes of {0} entity.", 
            context.ChangeTracker.Entries().Count());
         var entries = context.ChangeTracker.Entries();

         foreach (var entry in entries) {
            Console.WriteLine("Entity Name: {0}", entry.Entity.GetType().Name);
            Console.WriteLine("Status: {0}", entry.State);
         }

         Console.ReadKey();
      }
   }
}

Когда приведенный выше пример скомпилирован и выполнен, вы получите следующий вывод.

Adding New Enrollment
Delete Student
Context tracking changes of 2 entity.
Entity Name: Enrollment
Status: Added
Entity Name: Student
Status: Deleted

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

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Цветные объекты

В Entity Framework Colored Entity в основном занимается изменением цвета сущности в конструкторе, чтобы разработчикам было легко идентифицировать связанные группы сущностей в конструкторе Visual Studio. Эта функция была впервые представлена ​​в Entity Framework 5.0.

  • Эта функция не имеет ничего общего с аспектами производительности.

  • Если у вас есть крупномасштабный проект и много сущностей в одном файле EDMX, то эта функция очень полезна для разделения ваших сущностей в разных модулях.

Эта функция не имеет ничего общего с аспектами производительности.

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

Если вы работаете с файлом edmx и открыли его в конструкторе, для изменения цвета выберите объект в окнах дизайна. Затем щелкните правой кнопкой мыши и выберите «Свойства».

Edmx File DesignerEdmx File

В окне «Свойства» выберите свойство «Цвет заливки».

Окно свойств цвета

Укажите цвет, используя правильное имя цвета, например, «Зеленый» или «RGB» (255, 128, 128), или вы также можете выбрать его из палитры цветов.

цвет

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

Несколько сущностей

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

  • Отображаемое имя
  • Отображаемое имя и тип

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

Формат собственности

Выберите «Формат скалярного свойства» → «Отображаемое имя и тип».

Скалярный формат собственности

Теперь вы можете видеть, что тип также отображается вместе с именем.

Entity Framework — первый подход к коду

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

  • Код первый
  • База данных сначала
  • Модель Первая

В этой главе мы кратко опишем подход «сначала код». Некоторые разработчики предпочитают работать с конструктором в коде, в то время как другие предпочитают просто работать с их кодом. Для этих разработчиков Entity Framework имеет рабочий процесс моделирования, называемый Code First.

  • Рабочий процесс моделирования Code First нацелен на несуществующую базу данных, и Code First создаст ее.

  • Его также можно использовать, если у вас пустая база данных, а затем Code First добавит в нее новые таблицы.

  • Code First позволяет определить вашу модель с использованием классов C # или VB.Net.

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

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

Его также можно использовать, если у вас пустая база данных, а затем Code First добавит в нее новые таблицы.

Code First позволяет определить вашу модель с использованием классов C # или VB.Net.

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

Код первый подход

Почему код первый?

  • Code First действительно состоит из набора частей головоломки. Во-первых, ваши классы домена.

  • Классы домена не имеют ничего общего с Entity Framework. Они просто предметы вашего бизнеса.

  • Таким образом, Entity Framework имеет контекст, который управляет взаимодействием между этими классами и вашей базой данных.

  • Контекст не является специфичным для Code First. Это особенность Entity Framework.

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

  • Все это происходит во время выполнения. Вы никогда не увидите эту модель, она просто в памяти.

  • Code First также имеет возможность использовать эту модель для создания базы данных, если вы хотите.

  • Он также может обновить базу данных, если модель изменится, используя функцию под названием Code First Migrations.

Code First действительно состоит из набора частей головоломки. Во-первых, ваши классы домена.

Классы домена не имеют ничего общего с Entity Framework. Они просто предметы вашего бизнеса.

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

Контекст не является специфичным для Code First. Это особенность Entity Framework.

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

Все это происходит во время выполнения. Вы никогда не увидите эту модель, она просто в памяти.

Code First также имеет возможность использовать эту модель для создания базы данных, если вы хотите.

Он также может обновить базу данных, если модель изменится, используя функцию под названием Code First Migrations.

Настройка среды

Чтобы начать работать с подходом EF Code First, вам необходимо установить следующие инструменты в вашей системе.

  • Visual Studio 2013 (.net Framework 4.5.2) или более поздняя версия.
  • MS SQL Server 2012 или более поздняя версия.
  • Entity Framework через пакет NuGet.

Установите EF через пакет NuGet

Шаг 1 — Сначала создайте консольное приложение из Файл → Создать → Проект…

Шаг 2 — Выберите Windows на левой панели и Консольное приложение на панели шаблонов.

Установка EF

Шаг 3 — введите EFCodeFirstDemo в качестве имени и выберите ОК.

Шаг 4 — Щелкните правой кнопкой мыши свой проект в обозревателе решений и выберите «Управление пакетами NuGet»…

NuGet Package Manager

Откроется диспетчер пакетов NuGet и начнется поиск EntityFramework. Будет выполнен поиск всех пакетов, связанных с Entity Framework.

Шаг 5 — Выберите EntityFramework и нажмите «Установить». Или из меню «Инструменты» выберите «Диспетчер пакетов NuGet», а затем «Консоль диспетчера пакетов». В окне консоли диспетчера пакетов введите следующую команду: Install-Package EntityFramework.

Установленная Entity Framework6

Когда установка будет завершена, вы увидите следующее сообщение в окне вывода «Успешно установлено« EntityFramework 6.1.2 »в EFCodeFirstDemo».

После установки EntityFramework.dll будет включен в ваш проект, как показано на следующем рисунке.

Entity Framework dll

Теперь вы готовы начать работу над подходом Code First.

Entity Framework — первый пример

Давайте определим очень простую модель с использованием классов. Мы просто определяем их в файле Program.cs, но в реальном приложении вы разделите ваши классы на отдельные файлы и, возможно, на отдельный проект. Ниже приведена модель данных, которую мы будем создавать с использованием подхода Code First.

Модель с использованием классов

Создать модель

Добавьте следующие три класса в файл Program.cs, используя следующий код для класса Student.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}
  • Свойство ID станет столбцом первичного ключа таблицы базы данных, соответствующей этому классу.

  • Свойство Enrollments является свойством навигации. Свойства навигации содержат другие объекты, связанные с этим объектом.

  • В этом случае свойство Enrollments сущности Student будет содержать все сущности Enrollment, связанные с этой сущностью Student.

  • Свойства навигации обычно определяются как виртуальные, чтобы они могли использовать определенные функции Entity Framework, такие как отложенная загрузка.

  • Если свойство навигации может содержать несколько объектов (как в отношениях «многие ко многим» или «один к одному»), его тип должен быть списком, в который можно добавлять, удалять и обновлять записи, например ICollection.

Свойство ID станет столбцом первичного ключа таблицы базы данных, соответствующей этому классу.

Свойство Enrollments является свойством навигации. Свойства навигации содержат другие объекты, связанные с этим объектом.

В этом случае свойство Enrollments сущности Student будет содержать все сущности Enrollment, связанные с этой сущностью Student.

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

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

Ниже приведена реализация для курса.

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Свойство Enrollments является свойством навигации. Сущность курса может быть связана с любым количеством сущностей зачисления.

Ниже приведена реализация класса Enumement и enum.

public enum Grade {
   A, B, C, D, F
}

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}
  • Свойство EnrollmentID будет первичным ключом.

  • Свойство Grade является перечислением. Знак вопроса после объявления типа Grade указывает, что свойство Grade имеет значение NULL.

  • Нулевая оценка отличается от нулевой оценки. Нуль означает, что оценка не известна или еще не была назначена.

  • Свойства StudentID и CourseID являются внешними ключами, а соответствующие свойства навигации — Student и Course.

  • Объект Enrollment связан с одним объектом Student и одним объектом Course, поэтому свойство может содержать только один объект Student и Course.

Свойство EnrollmentID будет первичным ключом.

Свойство Grade является перечислением. Знак вопроса после объявления типа Grade указывает, что свойство Grade имеет значение NULL.

Нулевая оценка отличается от нулевой оценки. Нуль означает, что оценка не известна или еще не была назначена.

Свойства StudentID и CourseID являются внешними ключами, а соответствующие свойства навигации — Student и Course.

Объект Enrollment связан с одним объектом Student и одним объектом Course, поэтому свойство может содержать только один объект Student и Course.

Создать базу данных контекста

Основным классом, который координирует функциональность Entity Framework для данной модели данных, является класс контекста базы данных, который позволяет запрашивать и сохранять данные. Вы можете создать этот класс, наследуя от класса DbContext и выставляя типизированный DbSet для каждого класса в нашей модели. Ниже приведена реализация класса MyContext, который является производным от класса DbContext.

public class MyContext : DbContext {
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

Ниже приведен полный код в файле Program.cs.

using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace EFCodeFirstDemo {

   class Program {
      static void Main(string[] args) {}
   }

   public enum Grade {
      A, B, C, D, F
   }

   public class Enrollment {
      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Grade? Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }

   public class Student {
      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
      public DateTime EnrollmentDate { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class Course {
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class MyContext : DbContext {
      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }

}

Приведенный выше код — это все, что нам нужно, чтобы начать хранить и извлекать данные. Давайте добавим некоторые данные и затем получим их. Ниже приведен код в методе main.

static void Main(string[] args) {

   using (var context = new MyContext()) {
      // Create and save a new Students
      Console.WriteLine("Adding new students");

      var student = new Student {
         FirstMidName = "Alain", LastName = "Bomer", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      };

      context.Students.Add(student);
		
      var student1 = new Student {
         FirstMidName = "Mark", LastName = "Upston", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      };

      context.Students.Add(student1);
      context.SaveChanges();

      // Display all Students from the database
      var students = (from s in context.Students 
         orderby s.FirstMidName select s).ToList<Student>();

      Console.WriteLine("Retrieve all Students from the database:");

      foreach (var stdnt in students) {
         string name = stdnt.FirstMidName + " " + stdnt.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
      }
		
      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
   }
}

Когда приведенный выше код будет выполнен, вы получите следующий вывод.

Adding new students
Retrieve all Students from the database:
ID: 1, Name: Alain Bomer
ID: 2, Name: Mark Upston
Press any key to exit...

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

  • Если доступен локальный экземпляр SQL Express, Code First создаст базу данных для этого экземпляра.

  • Если SQL Express недоступен, Code First попытается использовать LocalDb.

  • База данных названа в честь полного имени производного контекста.

Если доступен локальный экземпляр SQL Express, Code First создаст базу данных для этого экземпляра.

Если SQL Express недоступен, Code First попытается использовать LocalDb.

База данных названа в честь полного имени производного контекста.

В нашем случае экземпляр SQL Express доступен, а имя базы данных — EFCodeFirstDemo.MyContext, как показано на следующем рисунке.

Экземпляр SQL Express

  • Это просто соглашения по умолчанию, и существуют различные способы изменить базу данных, которую использует Code First.

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

  • Имена столбцов и тип данных также соответствуют свойствам соответствующих классов домена.

Это просто соглашения по умолчанию, и существуют различные способы изменить базу данных, которую использует Code First.

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

Имена столбцов и тип данных также соответствуют свойствам соответствующих классов домена.

Инициализация базы данных

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

Инициализация базы данных

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

  • Нет параметра
  • Имя базы данных
  • Имя строки подключения

Нет параметра

Если вы укажете базовый конструктор класса контекста без каких-либо параметров, как показано в приведенном выше примере, тогда структура сущностей создаст базу данных на локальном сервере SQLEXPRESS с именем {Namespace}. {Имя класса контекста}.

В приведенном выше примере база данных, которая создается автоматически, имеет имя EFCodeFirstDemo.MyContext. Если вы посмотрите на имя, вы обнаружите, что EFCodeFirstDemo является пространством имен, а MyContext является именем класса контекста, как показано в следующем коде.

public class MyContext : DbContext {
   public MyContext() : base() {}

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

Имя базы данных

Если вы передадите имя базы данных в качестве параметра в базовом конструкторе класса контекста, то Code First снова автоматически создаст базу данных, но на этот раз это будет имя, переданное в качестве параметра в базовом конструкторе на локальном сервере базы данных SQLEXPRESS. ,

В следующем коде MyContextDB указывается в качестве параметра в базовом конструкторе. Если запустить ваше приложение, то база данных с именем MyContextDB будет создана на вашем локальном сервере SQL.

public class MyContext : DbContext {
   public MyContext() : base("MyContextDB") {}
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

Имя строки подключения

Это простой способ указать DbContext использовать сервер базы данных, отличный от SQL Express или LocalDb. Вы можете поместить строку подключения в файл app.config.

  • Если имя строки соединения совпадает с именем вашего контекста (либо с квалификацией пространства имен, либо без нее), то она будет найдена DbContext при использовании конструктора без параметра.

  • Если имя строки подключения отличается от имени вашего контекста, вы можете указать DbContext использовать это подключение в режиме Code First, передав имя строки подключения конструктору DbContext.

Если имя строки соединения совпадает с именем вашего контекста (либо с квалификацией пространства имен, либо без нее), то она будет найдена DbContext при использовании конструктора без параметра.

Если имя строки подключения отличается от имени вашего контекста, вы можете указать DbContext использовать это подключение в режиме Code First, передав имя строки подключения конструктору DbContext.

public class MyContext : DbContext {
   public MyContext() : base("name = MyContextDB") {}
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}
  • В приведенном выше коде фрагмент строки подключения класса контекста указан в качестве параметра в базовом конструкторе.

  • Имя строки подключения должно начинаться с «name =», в противном случае оно будет считаться именем базы данных.

  • Эта форма делает явным, что вы ожидаете, что строка соединения будет найдена в вашем файле конфигурации. Исключение будет выдано, если строка подключения с указанным именем не найдена.

В приведенном выше коде фрагмент строки подключения класса контекста указан в качестве параметра в базовом конструкторе.

Имя строки подключения должно начинаться с «name =», в противном случае оно будет считаться именем базы данных.

Эта форма делает явным, что вы ожидаете, что строка соединения будет найдена в вашем файле конфигурации. Исключение будет выдано, если строка подключения с указанным именем не найдена.

<connectionStrings>
   <add name = "MyContextDB"
      connectionString = "Data Source =.;Initial Catalog = EFMyContextDB;Integrated Security = true"
      providerName = "System.Data.SqlClient"/>
</connectionStrings>
  • Имя базы данных в строке подключения в app.config — EFMyContextDB . CodeFirst создаст новую базу данных EFMyContextDB или использует существующую базу данных EFMyContextDB на локальном сервере SQL.

Имя базы данных в строке подключения в app.config — EFMyContextDB . CodeFirst создаст новую базу данных EFMyContextDB или использует существующую базу данных EFMyContextDB на локальном сервере SQL.

Доменные классы

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

  • Аннотации данных
  • Свободный API

Аннотации данных

DataAnnotations используется для настройки ваших классов, которые будут выделять наиболее часто используемые конфигурации. Аннотации данных также понимаются рядом приложений .NET, таких как ASP.NET MVC, которые позволяют этим приложениям использовать одни и те же аннотации для проверки на стороне клиента.

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

public class Enrollment {

   [Key]
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }

   [ForeignKey("CourseID")]
   public virtual Course Course { get; set; }

   [ForeignKey("ID")]
   public virtual Student Student { get; set; }
}

Свободный API

Большая часть конфигурации модели может быть выполнена с использованием простых аннотаций данных. Свободный API — это расширенный способ задания конфигурации модели, который охватывает все, что могут делать аннотации данных, в дополнение к некоторым более сложным конфигурациям, невозможным для аннотаций данных. Аннотации данных и свободный API могут использоваться вместе.

Для доступа к свободному API вы переопределяете метод OnModelCreating в DbContext. Теперь давайте переименуем имя столбца в таблице ученика из FirstMidName в FirstName, как показано в следующем коде.

public class MyContext : DbContext {

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
         .HasColumnName("FirstName");
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

Entity Framework — Аннотации данных

DataAnnotations используется для настройки классов, которые будут выделять наиболее часто используемые конфигурации. Аннотации данных также понимаются рядом приложений .NET, таких как ASP.NET MVC, который позволяет этим приложениям использовать одни и те же аннотации для проверки на стороне клиента. Атрибуты DataAnnotation переопределяют соглашения CodeFirst по умолчанию.

System.ComponentModel.DataAnnotations включает следующие атрибуты, которые влияют на обнуляемость или размер столбца.

  • ключ
  • Отметка
  • ConcurrencyCheck
  • необходимые
  • MinLength
  • Максимальная длина
  • StringLength

Пространство имен System.ComponentModel.DataAnnotations.Schema содержит следующие атрибуты, которые влияют на схему базы данных.

  • Таблица
  • колонка
  • Индекс
  • Иностранный ключ
  • NotMapped
  • InverseProperty

ключ

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

  • Соглашение заключается в поиске свойства с именем «Id» или свойства, которое объединяет имя класса и «Id», например «StudentId».

  • Свойство будет сопоставлено столбцу первичного ключа в базе данных.

  • Классы Student, Course и Enrollment следуют этой конвенции.

Соглашение заключается в поиске свойства с именем «Id» или свойства, которое объединяет имя класса и «Id», например «StudentId».

Свойство будет сопоставлено столбцу первичного ключа в базе данных.

Классы Student, Course и Enrollment следуют этой конвенции.

Теперь давайте предположим, что класс Student использовал имя StdntID вместо ID. Если Code First не найдет свойство, соответствующее этому соглашению, оно выдаст исключение из-за требования Entity Framework о том, что у вас должно быть ключевое свойство. Вы можете использовать аннотацию ключа, чтобы указать, какое свойство будет использоваться в качестве EntityKey.

Давайте посмотрим на следующий код класса Student, который содержит StdntID, но он не следует стандартному соглашению Code First. Поэтому, чтобы справиться с этим, добавлен атрибут Key, который сделает его первичным ключом.

public class Student {

   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Когда вы запустите свое приложение и загляните в свою базу данных в SQL Server Explorer, вы увидите, что первичным ключом теперь является StdntID в таблице студентов.

Основной ключ

Entity Framework также поддерживает составные ключи. Составные ключи также являются первичными ключами, состоящими из нескольких свойств. Например, у вас есть класс DrivingLicense, первичный ключ которого представляет собой комбинацию LicenseNumber и IssuingCountry.

public class DrivingLicense {

   [Key, Column(Order = 1)]
   public int LicenseNumber { get; set; }
   [Key, Column(Order = 2)]
   public string IssuingCountry { get; set; }
   public DateTime Issued { get; set; }
   public DateTime Expires { get; set; }
}

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

Аннотация колонки

Отметка

Code First будет обрабатывать свойства Timestamp так же, как свойства ConcurrencyCheck, но также будет гарантировать, что поле базы данных, которое код генерирует первым, не обнуляется.

  • Для проверки параллелизма чаще используются поля строк и меток времени.

  • Вместо того, чтобы использовать аннотацию ConcurrencyCheck, вы можете использовать более конкретную аннотацию TimeStamp, если типом свойства является байтовый массив.

  • Вы можете иметь только одно свойство отметки времени в данном классе.

Для проверки параллелизма чаще используются поля строк и меток времени.

Вместо того, чтобы использовать аннотацию ConcurrencyCheck, вы можете использовать более конкретную аннотацию TimeStamp, если типом свойства является байтовый массив.

Вы можете иметь только одно свойство отметки времени в данном классе.

Давайте рассмотрим простой пример, добавив свойство TimeStamp в класс Course.

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
   [Timestamp]
   public byte[] TStamp { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Как видно из приведенного выше примера, атрибут Timestamp применяется к свойству Byte [] класса Course. Итак, Code First создаст столбец отметки времени TStamp в таблице Courses.

ConcurrencyCheck

Аннотация ConcurrencyCheck позволяет пометить одно или несколько свойств, которые будут использоваться для проверки параллелизма в базе данных, когда пользователь редактирует или удаляет объект. Если вы работали с EF Designer, это соответствует настройке свойства ConcurrencyMode свойства Fixed.

Давайте рассмотрим простой пример того, как работает ConcurrencyCheck, добавив его в свойство Title в классе Course.

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   public string Title { get; set; }
   public int Credits { get; set; }
   [Timestamp, DataType("timestamp")]
   public byte[] TimeStamp { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

В приведенном выше классе Course атрибут ConcurrencyCheck применяется к существующему свойству Title. Теперь Code First будет включать столбец Title в команде update для проверки оптимистичного параллелизма, как показано в следующем коде.

exec sp_executesql N'UPDATE [dbo].[Courses]
   SET [Title] = @0
   WHERE (([CourseID] = @1) AND ([Title] = @2))
   ',N'@0 nvarchar(max) ,@1 int,@2 nvarchar(max) ',@0=N'Maths',@1=1,@2=N'Calculus'
go

Обязательная аннотация

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

public class Student {

   [Key]
   public int StdntID { get; set; }

   [Required]
   public string LastName { get; set; }

   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Как видно из приведенного выше примера, атрибут Required применяется к FirstMidName и LastName. Таким образом, Code First создаст столбцы NOT NULL FirstMidName и LastName в таблице учеников, как показано на следующем рисунке.

Ненулевой

Максимальная длина

Атрибут MaxLength позволяет указать дополнительные проверки свойств. Его можно применять к свойству типа строки или массива класса домена. EF Code First установит размер столбца, как указано в атрибуте MaxLength.

Давайте посмотрим на следующий класс Course, в котором атрибут MaxLength (24) применяется к свойству Title.

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Когда вы запустите указанное выше приложение, Code First создаст заголовок столбца nvarchar (24) в таблице CourseId, как показано на следующем рисунке.

Колонна Нварчар

Когда пользователь устанавливает заголовок, который содержит более 24 символов, тогда EF сгенерирует EntityValidationError.

MinLength

Атрибут MinLength также позволяет вам указать дополнительные проверки свойств, как вы это делали с MaxLength. Атрибут MinLength также можно использовать с атрибутом MaxLength, как показано в следующем коде.

public class Course {

   public int CourseID { get; set; }
   [ConcurrencyCheck]
   [MaxLength(24) , MinLength(5)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

EF выбросит EntityValidationError, если вы установите значение свойства Title меньше указанной длины в атрибуте MinLength или больше указанной длины в атрибуте MaxLength.

StringLength

StringLength также позволяет указывать дополнительные проверки свойств, такие как MaxLength. Единственное отличие состоит в том, что атрибут StringLength можно применять только к свойству строкового типа классов Domain.

public class Course {

   public int CourseID { get; set; }
   [StringLength (24)]
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Entity Framework также проверяет значение свойства для атрибута StringLength. Если пользователь устанавливает заголовок, содержащий более 24 символов, то EF сгенерирует EntityValidationError.

Таблица

По умолчанию Code First создает имя таблицы, подобное имени класса. Если вы позволяете Code First создать базу данных, а также хотите изменить имя создаваемых таблиц. Тогда —

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

  • Атрибут таблицы переопределяет это соглашение по умолчанию.

  • EF Code First создаст таблицу с указанным именем в атрибуте Table для данного класса домена.

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

Атрибут таблицы переопределяет это соглашение по умолчанию.

EF Code First создаст таблицу с указанным именем в атрибуте Table для данного класса домена.

Давайте посмотрим на следующий пример, в котором класс называется «Студент», и по соглашению Code First предполагает, что он будет сопоставлен с таблицей «Студенты». Если это не так, вы можете указать имя таблицы с атрибутом Table, как показано в следующем коде.

[Table("StudentsInfo")]
public class Student {

   [Key]
   public int StdntID { get; set; }
   [Required]
   public string LastName { get; set; }
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

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

StudentsInfo

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

[Table("StudentsInfo", Schema = "Admin")] 
public class Student {

   [Key]
   public int StdntID { get; set; }
   [Required]
   public string LastName { get; set; }
   [Required]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Как видно из приведенного выше примера, таблица указана с помощью схемы администратора. Теперь Code First создаст таблицу StudentsInfo в схеме администратора, как показано на следующем рисунке.

Схема администратора

колонка

Он также совпадает с атрибутом таблицы, но атрибут таблицы переопределяет поведение таблицы, а атрибут столбца переопределяет поведение столбца. По умолчанию Code First создает имя столбца, подобное имени свойства. Если вы позволяете Code First создать базу данных, а также хотите изменить имя столбцов в ваших таблицах. Тогда —

  • Атрибут столбца переопределяет соглашение по умолчанию.

  • EF Code First создаст столбец с указанным именем в атрибуте Column для данного свойства.

Атрибут столбца переопределяет соглашение по умолчанию.

EF Code First создаст столбец с указанным именем в атрибуте Column для данного свойства.

Давайте рассмотрим следующий пример, в котором свойство называется FirstMidName, и, по соглашению, Code First предполагает, что оно будет сопоставлено со столбцом с именем FirstMidName.

Если это не так, вы можете указать имя столбца с атрибутом Column, как показано в следующем коде.

public class Student {

   public int ID { get; set; }
   public string LastName { get; set; }
   [Column("FirstName")]
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

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

Имя

Индекс

Атрибут Index был введен в Entity Framework 6.1. Если вы используете более раннюю версию, информация в этом разделе не применяется.

  • Вы можете создать индекс для одного или нескольких столбцов, используя IndexAttribute.

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

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

  • Индексирование — это новая функция в Entity Framework, позволяющая повысить производительность приложения Code First, сократив время, необходимое для запроса данных из базы данных.

  • Вы можете добавить индексы в свою базу данных, используя атрибут Index, и переопределить параметры по умолчанию Unique и Clustered, чтобы получить индекс, наиболее подходящий для вашего сценария.

  • По умолчанию индекс будет иметь имя IX_ <имя свойства>

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

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

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

Индексирование — это новая функция в Entity Framework, позволяющая повысить производительность приложения Code First, сократив время, необходимое для запроса данных из базы данных.

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

По умолчанию индекс будет иметь имя IX_ <имя свойства>

Давайте посмотрим на следующий код, в котором атрибут Index добавлен в класс Course for Credits.

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Вы можете видеть, что атрибут Index применяется к свойству Credits. Когда таблица будет сгенерирована, вы увидите IX_Credits в индексах.

IX Кредиты

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

public class Course {
   public int CourseID { get; set; }
   [Index(IsUnique = true)]
	
   public string Title { get; set; }
   [Index]
	
   public int Credits { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Иностранный ключ

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

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

public class Student {
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

При создании базы данных Code First видит свойство StudentID в классе Enrollment и распознает его по соглашению, что оно соответствует имени класса плюс «ID», как внешний ключ к классу Student. Однако в классе Student отсутствует свойство StudentID, но свойство StdntID относится к классу Student.

Решением для этого является создание свойства навигации в Enrollment и использование ForeignKey DataAnnotation, чтобы помочь Code First понять, как построить отношения между двумя классами, как показано в следующем коде.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
	
   public Grade? Grade { get; set; }
   public virtual Course Course { get; set; }
   [ForeignKey("StudentID")]
	
   public virtual Student Student { get; set; }
}

Теперь вы можете видеть, что атрибут ForeignKey применяется к свойству навигации.

Атрибут ForeignKey

NotMapped

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

public class Student {
   [Key]
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
	
   public DateTime EnrollmentDate { get; set; }
   [NotMapped]

   public int FatherName { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

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

Атрибут NotMapped

Code First не создаст столбец для свойства, в котором нет ни методов получения, ни установки, как показано в следующем примере свойств Address и Age класса Student.

InverseProperty

InverseProperty используется, когда у вас есть несколько отношений между классами. В классе Enrollment вы можете отслеживать, кто записался на текущий курс и предыдущий курс. Давайте добавим два свойства навигации для класса Enrollment.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course CurrCourse { get; set; }
   public virtual Course PrevCourse { get; set; }
   public virtual Student Student { get; set; }
}

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

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]

   public int Credits { get; set; }
   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

Code First создает столбец внешнего ключа {Имя класса} _ {Первичный ключ}, если свойство внешнего ключа не включено в определенный класс, как показано в приведенных выше классах. Когда база данных будет сгенерирована, вы увидите следующие внешние ключи.

Иностранные ключи

Как вы можете видеть, сначала Code не может сопоставить свойства двух классов самостоятельно. Таблица базы данных для заявок должна иметь один внешний ключ для CurrCourse и один для PrevCourse, но Code First создаст четыре свойства внешнего ключа, т.е.

  • CurrCourse _CourseID
  • PrevCourse _CourseID
  • Course_CourseID и
  • Course_CourseID1

Чтобы исправить эти проблемы, вы можете использовать аннотацию InverseProperty, чтобы указать выравнивание свойств.

public class Course {

   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]

   public int Credits { get; set; }
   [InverseProperty("CurrCourse")]

   public virtual ICollection<Enrollment> CurrEnrollments { get; set; }
   [InverseProperty("PrevCourse")]

   public virtual ICollection<Enrollment> PrevEnrollments { get; set; }
}

Как вы можете видеть, атрибут InverseProperty применяется в указанном выше классе Course, указывая, к какому ссылочному свойству класса Enrollment он принадлежит. Теперь Code First сгенерирует базу данных и создаст только два столбца внешнего ключа в таблице Enrollments, как показано на следующем рисунке.

Столбцы внешнего ключа

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Свободный API

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

  • Свободный API — это еще один способ настройки классов вашего домена.

  • Доступ к API Code First Fluent чаще всего осуществляется путем переопределения метода OnModelCreating в производном DbContext.

  • Свободный API предоставляет больше возможностей для конфигурации, чем DataAnnotations. Fluent API поддерживает следующие типы отображений.

Свободный API — это еще один способ настройки классов вашего домена.

Доступ к API Code First Fluent чаще всего осуществляется путем переопределения метода OnModelCreating в производном DbContext.

Свободный API предоставляет больше возможностей для конфигурации, чем DataAnnotations. Fluent API поддерживает следующие типы отображений.

В этой главе мы продолжим с простым примером, который содержит классы Student, Course и Enrollment и один контекстный класс с именем MyContext, как показано в следующем коде.

using System.Data.Entity; 
using System.Linq; 
using System.Text;
using System.Threading.Tasks;  

namespace EFCodeFirstDemo {

   class Program {
      static void Main(string[] args) {}
   }
   
   public enum Grade {
      A, B, C, D, F
   }

   public class Enrollment {
      public int EnrollmentID { get; set; }
      public int CourseID { get; set; }
      public int StudentID { get; set; }
      public Grade? Grade { get; set; }
		
      public virtual Course Course { get; set; }
      public virtual Student Student { get; set; }
   }

   public class Student {
      public int ID { get; set; }
      public string LastName { get; set; }
      public string FirstMidName { get; set; }
		
      public DateTime EnrollmentDate { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class Course {
      public int CourseID { get; set; }
      public string Title { get; set; }
      public int Credits { get; set; }
		
      public virtual ICollection<Enrollment> Enrollments { get; set; }
   }

   public class MyContext : DbContext {
      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
   }

}	  

Для доступа к Fluent API вам необходимо переопределить метод OnModelCreating в DbContext. Давайте рассмотрим простой пример, в котором мы переименуем имя столбца в таблице ученика из FirstMidName в FirstName, как показано в следующем коде.

public class MyContext : DbContext {

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
      .HasColumnName("FirstName");}

      public virtual DbSet<Course> Courses { get; set; }
      public virtual DbSet<Enrollment> Enrollments { get; set; }
      public virtual DbSet<Student> Students { get; set; }
}

DbModelBuilder используется для отображения классов CLR в схему базы данных. Это основной класс, на котором вы можете настроить все классы вашего домена. Этот основанный на коде подход к построению модели данных объекта (EDM) известен как Code First.

Fluent API предоставляет ряд важных методов для настройки сущностей и его свойств для переопределения различных соглашений Code First. Ниже приведены некоторые из них.

Старший Название и описание метода
1

ComplexType <TComplexType>

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

2

Entity <TEntityType>

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

3

HasKey <TKey>

Настраивает свойства первичного ключа для этого типа объекта.

4

HasMany <TTargetEntity>

Настраивает множество отношений из этого типа объекта.

5

HasOptional <TTargetEntity>

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

6

HasRequired <TTargetEntity>

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

7

Игнорировать <TProperty>

Исключает свойство из модели, чтобы оно не отображалось в базе данных. (Унаследовано от StructuralTypeConfiguration <TStructuralType>)

8

Свойство <T>

Настраивает свойство struct, определенное для этого типа. (Унаследовано от StructuralTypeConfiguration <TStructuralType>)

9

ToTable (String)

Настраивает имя таблицы, с которой сопоставляется этот тип сущности.

ComplexType <TComplexType>

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

Entity <TEntityType>

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

HasKey <TKey>

Настраивает свойства первичного ключа для этого типа объекта.

HasMany <TTargetEntity>

Настраивает множество отношений из этого типа объекта.

HasOptional <TTargetEntity>

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

HasRequired <TTargetEntity>

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

Игнорировать <TProperty>

Исключает свойство из модели, чтобы оно не отображалось в базе данных. (Унаследовано от StructuralTypeConfiguration <TStructuralType>)

Свойство <T>

Настраивает свойство struct, определенное для этого типа. (Унаследовано от StructuralTypeConfiguration <TStructuralType>)

ToTable (String)

Настраивает имя таблицы, с которой сопоставляется этот тип сущности.

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

  • Entity Mapping
  • Картирование свойств

Entity Mapping

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

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

  • Первое, что нужно переопределить, — метод OnModelCreating, который позволяет работать с modelBuilder.

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

Первое, что нужно переопределить, — метод OnModelCreating, который позволяет работать с modelBuilder.

Схема по умолчанию

Схема по умолчанию — dbo, когда база данных генерируется. Вы можете использовать метод HasDefaultSchema в DbModelBuilder, чтобы указать схему базы данных, которая будет использоваться для всех таблиц, хранимых процедур и т. Д.

Давайте посмотрим на следующий пример, в котором применяется схема администратора.

public class MyContext : DbContext {
   public MyContext() : base("name = MyContextDB") {}

   protected override void OnModelCreating(DbModelBuilder modelBuilder) {
      //Configure default schema
      modelBuilder.HasDefaultSchema("Admin");
   }
	
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

Сопоставить объект с таблицей

С соглашением по умолчанию Code First создаст таблицы базы данных с именем свойств DbSet в классе контекста, таком как Курсы, Зачисления и Студенты. Но если вам нужны другие имена таблиц, вы можете переопределить это соглашение и предоставить другое имя таблицы, отличное от свойств DbSet, как показано в следующем коде.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().ToTable("StudentData");
   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

Когда база данных будет сгенерирована, вы увидите имя таблицы, указанное в методе OnModelCreating.

Метод OnModel

Разделение сущностей (сопоставление сущностей с несколькими таблицами)

Разделение сущностей позволяет объединять данные, поступающие из нескольких таблиц, в один класс, и его можно использовать только с таблицами, между которыми существует отношение «один к одному». Давайте рассмотрим следующий пример, в котором информация об ученике отображается в две таблицы.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Map entity to table
   modelBuilder.Entity<Student>().Map(sd ⇒ {
      sd.Properties(p ⇒ new { p.ID, p.FirstMidName, p.LastName });
      sd.ToTable("StudentData");
   })

   .Map(si ⇒ {
      si.Properties(p ⇒ new { p.ID, p.EnrollmentDate });
      si.ToTable("StudentEnrollmentInfo");
   });

   modelBuilder.Entity<Course>().ToTable("CourseDetail");
   modelBuilder.Entity<Enrollment>().ToTable("EnrollmentInfo");
}

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

  • StudentData — содержит имя и фамилию ученика.

  • StudentEnrollmentInfo — Содержит EnrollmentDate.

StudentData — содержит имя и фамилию ученика.

StudentEnrollmentInfo — Содержит EnrollmentDate.

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

Разделение сущностей

Картирование свойств

Метод Property используется для настройки атрибутов для каждого свойства, принадлежащего сущности или сложному типу. Метод Property используется для получения объекта конфигурации для данного свойства. Вы также можете сопоставить и настроить свойства классов вашего домена с помощью Fluent API.

Конфигурирование первичного ключа

Соглашение по умолчанию для первичных ключей —

  • Класс определяет свойство, имя которого «ID» или «Id»
  • Имя класса, за которым следует «ID» или «Id»

Если ваш класс не следует соглашениям по умолчанию для первичного ключа, как показано в следующем коде класса Student —

public class Student {
   public int StdntID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

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

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
	
   // Configure Primary Key
   modelBuilder.Entity<Student>().HasKey<int>(s ⇒ s.StdntID); 
}

Настроить столбец

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

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure EnrollmentDate Column
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate)
	
   .HasColumnName("EnDate")
   .HasColumnType("DateTime")
   .HasColumnOrder(2);
}

Настроить свойство MaxLength

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

protected override void OnModelCreating(DbModelBuilder modelBuilder) {
   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).HasMaxLength(24);
}

Настроить свойство Null или NotNull

В следующем примере свойство Course Title является обязательным, поэтому для создания столбца NotNull используется метод IsRequired. Аналогично, Student EnrollmentDate является необязательным, поэтому мы будем использовать метод IsOptional, чтобы разрешить нулевое значение в этом столбце, как показано в следующем коде.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");
   modelBuilder.Entity<Course>().Property(p ⇒ p.Title).IsRequired();
   modelBuilder.Entity<Student>().Property(p ⇒ p.EnrollmentDate).IsOptional();
	
   //modelBuilder.Entity<Student>().Property(s ⇒ s.FirstMidName)
   //.HasColumnName("FirstName"); 
}

Настройка отношений

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

  • Если вы используете соглашения об именах Code First, в большинстве случаев вы можете полагаться на Code First для установки отношений между вашими таблицами на основе внешних ключей и свойств навигации.

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

  • Некоторые из них доступны в аннотациях данных, и вы можете применить некоторые даже более сложные с помощью Fluent API.

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

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

Некоторые из них доступны в аннотациях данных, и вы можете применить некоторые даже более сложные с помощью Fluent API.

Настроить отношения один-к-одному

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

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

  • В отношении «один к одному» первичный ключ действует дополнительно как внешний ключ, и для каждой таблицы нет отдельного столбца внешнего ключа.

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

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

В отношении «один к одному» первичный ключ действует дополнительно как внешний ключ, и для каждой таблицы нет отдельного столбца внешнего ключа.

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

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

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Как видно из приведенного выше кода, атрибуты Key и ForeignKey используются для свойства ID в классе StudentLogIn, чтобы пометить его как первичный ключ, а также как внешний ключ.

Чтобы настроить отношение «один к нулю» или «одно» между Student и StudentLogIn с помощью Fluent API, необходимо переопределить метод OnModelCreating, как показано в следующем коде.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   
   .HasOptional(s ⇒ s.StudentLogIn) //StudentLogIn is optional
   .WithRequired(t ⇒ t.Student); // Create inverse relationship
}

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

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure ID as PK for StudentLogIn
   modelBuilder.Entity<StudentLogIn>()
   .HasKey(s ⇒ s.ID);

   // Configure ID as FK for StudentLogIn
   modelBuilder.Entity<Student>()
   .HasRequired(r ⇒ r.Student)
   .WithOptional(s ⇒ s.StudentLogIn);  
}

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

Созданные отношения

Настройте отношения один-ко-многим

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

  • В этом типе отношений строка в таблице A может иметь много совпадающих строк в таблице B, но строка в таблице B может иметь только одну соответствующую строку в таблице A.

  • Внешний ключ определен в таблице, представляющей конец множества отношений.

  • Например, на приведенной выше диаграмме таблицы «Учащийся» и «Зачисление» имеют отношение «один-ко-многим», у каждого учащегося может быть много зачислений, но каждая запись принадлежит только одному учащемуся.

В этом типе отношений строка в таблице A может иметь много совпадающих строк в таблице B, но строка в таблице B может иметь только одну соответствующую строку в таблице A.

Внешний ключ определен в таблице, представляющей конец множества отношений.

Например, на приведенной выше диаграмме таблицы «Учащийся» и «Зачисление» имеют отношение «один-ко-многим», у каждого учащегося может быть много зачислений, но каждая запись принадлежит только одному учащемуся.

Ниже приведены «Студент» и «Регистрация», которые имеют отношение «один ко многим», но внешний ключ в таблице регистрации не соответствует стандартным соглашениям Code First.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
	
   //StdntID is not following code first conventions name
   public int StdntID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }
}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual StudentLogIn StudentLogIn { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

В этом случае для настройки отношения «один ко многим» с помощью Fluent API необходимо использовать метод HasForeignKey, как показано в следующем коде.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   //Configure FK for one-to-many relationship
   modelBuilder.Entity<Enrollment>()

   .HasRequired<Student>(s ⇒ s.Student)
   .WithMany(t ⇒ t.Enrollments)
   .HasForeignKey(u ⇒ u.StdntID);  
}

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

HasRequired метод

В приведенном выше примере метод HasRequired указывает, что свойство навигации Student должно иметь значение Null. Таким образом, вы должны назначать объект «Студент с регистрацией» каждый раз, когда добавляете или обновляете регистрацию. Для этого нам нужно использовать метод HasOptional вместо метода HasRequired.

Настройте отношения «многие ко многим»

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

  • Вы можете создать такое отношение, определив третью таблицу, называемую соединительной таблицей, первичный ключ которой состоит из внешних ключей из таблицы A и таблицы B.

  • Например, таблица Student и таблица Course имеют отношение «многие ко многим».

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

Например, таблица Student и таблица Course имеют отношение «многие ко многим».

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

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Course> Courses { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   public int Credits { get; set; }
	
   public virtual ICollection<Student> Students { get; set; }
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

Чтобы настроить отношения «многие ко многим» между студентом и курсом, вы можете использовать Fluent API, как показано в следующем коде.

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship
   modelBuilder.Entity<Student>()
   .HasMany(s ⇒ s.Courses) 
   .WithMany(s ⇒ s.Students);
}

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

Присоединиться к таблице

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

protected override void OnModelCreating(DbModelBuilder modelBuilder) {

   //Configure default schema
   modelBuilder.HasDefaultSchema("Admin");

   // Configure many-to-many relationship 
   modelBuilder.Entity<Student>()

   .HasMany(s ⇒ s.Courses)
   .WithMany(s ⇒ s.Students)
   
   .Map(m ⇒ {
      m.ToTable("StudentCoursesTable");
      m.MapLeftKey("StudentID");
      m.MapRightKey("CourseID");
   }); 
}

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

Присоединиться к таблице

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — База данных семян

В Entity Framework Seed был представлен в EF 4.1 и работает с инициализаторами базы данных. Общая идея Seed Method заключается в инициализации данных в базе данных, которая создается Code First или развивается посредством Migrations. Эти данные часто являются тестовыми данными, но также могут быть справочными данными, такими как списки известных студентов, курсы и т. Д. Когда данные инициализируются, они выполняют следующее:

  • Проверяет, существует ли целевая база данных.
  • Если это так, то текущая модель Code First сравнивается с моделью, хранящейся в метаданных в базе данных.
  • База данных удаляется, если текущая модель не соответствует модели в базе данных.
  • База данных создается, если она была отброшена или вообще не существовала.
  • Если база данных была создана, то вызывается метод Seed инициализатора.

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

private class UniDBInitializer<T> : DropCreateDatabaseAlways<MyContext> {

   protected override void Seed(MyContext context) {

      IList<Student> students = new List<Student>();

      students.Add(new Student() {
         FirstMidName = "Andrew", 
         LastName = "Peters", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      students.Add(new Student() {
         FirstMidName = "Brice", 
         LastName = "Lambson", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      students.Add(new Student() {
         FirstMidName = "Rowan", 
         LastName = "Miller", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
      });

      foreach (Student student in students)
      context.Students.Add(student);
      base.Seed(context);
   }
}

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

public MyContext() : base("name=MyContextDB") {
   Database.SetInitializer<MyContext>(new UniDBInitializer<MyContext>());
}

Ниже приведена полная реализация класса MyContext, который также содержит класс инициализатора БД.

public class MyContext : DbContext {

   public MyContext() : base("name=MyContextDB") {
      Database.SetInitializer<MyContext>(new UniDBInitializer<MyContext>());
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
	
   private class UniDBInitializer<T> : DropCreateDatabaseAlways<MyContext> {

      protected override void Seed(MyContext context) {

         IList<Student> students = new List<Student>();
			
         students.Add(new Student() {
            FirstMidName = "Andrew", 
            LastName = "Peters", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString()) 
         });

         students.Add(new Student() {
            FirstMidName = "Brice", 
            LastName = "Lambson", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         students.Add(new Student() {
            FirstMidName = "Rowan", 
            LastName = "Miller", 
            EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         });

         foreach (Student student in students)
         context.Students.Add(student);
         base.Seed(context);
      }
   } 
}

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

Данные в базе данных

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Code First Migration

Entity Framework 4.3 включает в себя новую функцию Code First Migrations, которая позволяет постепенно развивать схему базы данных по мере изменения модели с течением времени. Для большинства разработчиков это является большим улучшением по сравнению с опциями инициализатора базы данных из выпусков 4.1 и 4.2, которые требуют ручного обновления базы данных или ее удаления и повторного создания при изменении модели.

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

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

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

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

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

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

Есть два вида миграции —

  • Автоматизированная миграция
  • Миграция на основе кода

Автоматизированная миграция

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

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

Когда вы используете подход Code First, у вас нет базы данных для вашего приложения.

В этом примере мы начнем с наших 3 основных классов, таких как ученик, курс и зачисление, как показано в следующем коде.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }

}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

Ниже приводится контекстный класс.

public class MyContext : DbContext {
   public MyContext() : base("MyContextDB") {}
   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }
}

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

Шаг 1 — Откройте Консоль менеджера пакетов из Сервиса → Менеджер пакетов NuGet → Консоль менеджера пакетов.

Шаг 2. Чтобы включить автоматическую миграцию, выполните следующую команду в консоли диспетчера пакетов.

PM> enable-migrations -EnableAutomaticMigrations:$true

команда

Шаг 3. После успешного выполнения команды она создает внутренний запечатанный класс Configuration в папке Migration вашего проекта, как показано в следующем коде.

namespace EFCodeFirstDemo.Migrations {

   using System;
   using System.Data.Entity;
   using System.Data.Entity.Migrations;
   using System.Linq;
	
   internal sealed class Configuration : DbMigrationsConfiguration<EFCodeFirstDemo.MyContext> {

      public Configuration() {
         AutomaticMigrationsEnabled = true;
         ContextKey = "EFCodeFirstDemo.MyContext";
      }

      protected override void Seed(EFCodeFirstDemo.MyContext context) {

         //  This method will be called after migrating to the latest version.
         //  You can use the DbSet<T>.AddOrUpdate() helper extension method
         //  to avoid creating duplicate seed data. E.g.

         //  context.People.AddOrUpdate(
            //  p ⇒ p.FullName, 
            //  new Person { FullName = "Andrew Peters" }, 
            //  new Person { FullName = "Brice Lambson" }, 
            //  new Person { FullName = "Rowan Miller" }
         //  );
      }
   }
}

Шаг 4 — Установите инициализатор базы данных в классе контекста с помощью новой стратегии инициализации БД MigrateDatabaseToLatestVersion.

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, 
         EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Шаг 5 — Вы настроили автоматическую миграцию. Когда вы выполняете свое приложение, оно автоматически позаботится о переносе, когда вы измените модель.

миграция

Шаг 6 — Как вы видите, одна системная таблица __MigrationHistory также создается в вашей базе данных с другими таблицами. В __MigrationHistory автоматическая миграция поддерживает историю изменений базы данных.

Шаг 7 — Когда вы добавите другой класс сущности в качестве класса вашего домена и запустите приложение, оно создаст таблицу в вашей базе данных. Давайте добавим следующий класс StudentLogIn.

public class StudentLogIn {
   [Key, ForeignKey("Student")]
   public int ID { get; set; }
   public string EmailID { get; set; }
   public string Password { get; set; }
	
   public virtual Student Student { get; set; }
}

Шаг 8 — Не забудьте добавить DBSet для вышеупомянутого класса в свой контекстный класс, как показано в следующем коде.

public virtual DbSet<StudentLogIn> StudentsLogIn { get; set; }

Шаг 9 — Запустите ваше приложение еще раз, и вы увидите, что таблица StudentsLogIn добавлена ​​в вашу базу данных.

StudentsLogIn

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

Шаг 10. Для обработки миграции свойства необходимо установить AutomaticMigrationDataLossAllowed = true в конструкторе класса конфигурации.

public Configuration() {
   AutomaticMigrationsEnabled = true;
   AutomaticMigrationDataLossAllowed = true;
   ContextKey = "EFCodeFirstDemo.MyContext";
}

Миграция на основе кода

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

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

  • Функция Code First Migrations решает эту проблему, позволяя Code First обновлять схему базы данных вместо ее удаления и повторного создания. Чтобы развернуть приложение, вам нужно включить миграцию.

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

Функция Code First Migrations решает эту проблему, позволяя Code First обновлять схему базы данных вместо ее удаления и повторного создания. Чтобы развернуть приложение, вам нужно включить миграцию.

Вот основное правило для переноса изменений в базу данных —

  • Включить миграцию
  • Добавить миграцию
  • Обновление базы данных

Давайте посмотрим на следующий пошаговый процесс миграции кода.

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

В этом примере мы снова начнем с наших 3 основных классов, таких как ученик, курс и зачисление, как показано в следующем коде.

public class Enrollment {
   public int EnrollmentID { get; set; }
   public int CourseID { get; set; }
   public int StudentID { get; set; }
   public Grade? Grade { get; set; }
	
   public virtual Course Course { get; set; }
   public virtual Student Student { get; set; }

}

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

public class Course {
   public int CourseID { get; set; }
   public string Title { get; set; }
   [Index]
   public int Credits { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

Ниже приводится контекстный класс.

public class MyContext : DbContext {

   public MyContext() : base("MyContextDB") {
      Database.SetInitializer(new MigrateDatabaseToLatestVersion<
         MyContext, EFCodeFirstDemo.Migrations.Configuration>("MyContextDB"));
   }

   public virtual DbSet<Course> Courses { get; set; }
   public virtual DbSet<Enrollment> Enrollments { get; set; }
   public virtual DbSet<Student> Students { get; set; }

}

Шаг 1. Перед запуском приложения необходимо включить миграцию.

Шаг 2 — Откройте Консоль диспетчера пакетов из меню Инструменты → Диспетчер пакетов NuGet → Консоль диспетчера пакетов.

Шаг 3 — Миграция уже включена, теперь добавьте миграцию в ваше приложение, выполнив следующую команду.

PM> add-migration "UniDB Schema"

Шаг 4. После успешного выполнения команды вы увидите, что в папке Migration был создан новый файл с именем параметра, переданного команде с префиксом временной метки, как показано на следующем рисунке.

Префикс TimeStamp

Шаг 5 — Вы можете создать или обновить базу данных с помощью команды «update-database».

PM> Update-Database -Verbose

Флаг «-Verbose» указывает, что операторы SQL применяются к целевой базе данных в консоли.

Шаг 6 — Давайте добавим еще одно свойство ‘Возраст’ в класс ученика и затем выполним оператор обновления.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public int Age { get; set; }
   public DateTime EnrollmentDate { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

}

Когда вы выполните PM → Update-Database — Verbose, когда команда будет успешно выполнена, вы увидите, что новый столбец Age добавлен в вашу базу данных.

Новая колонна эпохи.

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — множественный DbContext

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

  • Множественный DbContext был впервые представлен в Entity Framework 6.0.
  • Несколько классов контекста могут принадлежать одной базе данных или двум различным базам данных.

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

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
}

public class MyStudentContext : DbContext {
   public MyStudentContext() : base("UniContextDB") {}
   public virtual DbSet<Student> Students { get; set; }
}

public class Teacher {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime HireDate { get; set; }
}

public class MyTeacherContext : DbContext {
   public MyTeacherContext() : base("UniContextDB") {}
   public virtual DbSet<Teacher> Teachers { get; set; }
}

Как видно из приведенного выше кода, есть две модели, которые называются «Ученик» и «Учитель». Каждый из них связан с определенным соответствующим классом контекста, т. Е. Student связан с MyStudentContext, а Teacher связан с MyTeacherContext.

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

  • enable-migrations -ContextTypeName <DbContext-Name-with-Namespaces> MigrationsDirectory: <Migrations-Directory-Name>

  • Add-Migration -configuration <DbContext-Migrations-Configuration-Class-with -Namespaces> <Migrations-Name>

  • Update-Database -configuration <DbContext-Migrations-Migrations-Configuration-Class-withNamespaces> -Verbose

enable-migrations -ContextTypeName <DbContext-Name-with-Namespaces> MigrationsDirectory: <Migrations-Directory-Name>

Add-Migration -configuration <DbContext-Migrations-Configuration-Class-with -Namespaces> <Migrations-Name>

Update-Database -configuration <DbContext-Migrations-Migrations-Configuration-Class-withNamespaces> -Verbose

Давайте включим миграцию для MyStudentContext, выполнив следующую команду в консоли диспетчера пакетов.

PM→ enable-migrations -ContextTypeName:EFCodeFirstDemo.MyStudentContext

Консоль диспетчера пакетов

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

PM→ add-migration -configuration EFCodeFirstDemo.Migrations.Configuration Initial

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

static void Main(string[] args) {

   using (var context = new MyStudentContext()) {
	
      //// Create and save a new Students
      Console.WriteLine("Adding new students");

      var student = new Student {
         FirstMidName = "Alain", 
         LastName = "Bomer", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 24
      };

      context.Students.Add(student);

      var student1 = new Student {
         FirstMidName = "Mark",
         LastName = "Upston", 
         EnrollmentDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 30
      };

      context.Students.Add(student1);
      context.SaveChanges();
      // Display all Students from the database
      var students = (from s in context.Students orderby s.FirstMidName
         select s).ToList<Student>();
		
      Console.WriteLine("Retrieve all Students from the database:");

      foreach (var stdnt in students) {
         string name = stdnt.FirstMidName + " " + stdnt.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", stdnt.ID, name);
      }

      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
   }

   using (var context = new MyTeacherContext()) {

      //// Create and save a new Teachers
      Console.WriteLine("Adding new teachers");

      var student = new Teacher {
         FirstMidName = "Alain", 
         LastName = "Bomer", 
         HireDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 24
      };

      context.Teachers.Add(student);

      var student1 = new Teacher {
         FirstMidName = "Mark", 
         LastName = "Upston", 
         HireDate = DateTime.Parse(DateTime.Today.ToString())
         //Age = 30
      };

      context.Teachers.Add(student1);
      context.SaveChanges();
  
      // Display all Teachers from the database
      var teachers = (from t in context.Teachers orderby t.FirstMidName
         select t).ToList<Teacher>();
		
      Console.WriteLine("Retrieve all teachers from the database:");

      foreach (var teacher in teachers) {
         string name = teacher.FirstMidName + " " + teacher.LastName;
         Console.WriteLine("ID: {0}, Name: {1}", teacher.ID, name);
      }

      Console.WriteLine("Press any key to exit...");
      Console.ReadKey();
   }
}

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

Исполняемый код

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.

Entity Framework — Вложенные типы сущностей

До Entity Framework 6 Entity Framework не распознавала объекты или сложные типы, которые были вложены в другие объекты или сложные типы. Когда Entity Framework сгенерировал модель, вложенные типы просто исчезли.

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

  • Давайте добавим свойство Identity, которое является типом Person. Person — это другая сущность, содержащая свойства BirthDate и FatherName.

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

  • Тип Person не является вложенным, как показано в следующем коде.

Давайте добавим свойство Identity, которое является типом Person. Person — это другая сущность, содержащая свойства BirthDate и FatherName.

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

Тип Person не является вложенным, как показано в следующем коде.

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
   public DateTime EnrollmentDate { get; set; }
   public Person Identity { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }
}

public class Person {

   public Person(string fatherName, DateTime birthDate) {
      FatherName = fatherName;
      BirthDate = birthDate;
   }
	
   public string FatherName { get; set; }
   public DateTime BirthDate { get; set; }
}

Entity Framework будет знать, как сохранить типы Person, когда он также используется в предыдущих версиях.

Используя Entity Framework Power Tool, мы увидим, как Entity Framework интерпретирует модель. Щелкните правой кнопкой мыши файл Program.cs и выберите Entity Framework → Просмотреть модель данных Entity (только для чтения).

Framework Power Tool

Теперь вы увидите, что свойство Identity определено в классе Student.

Собственность идентичности

Если этот класс Person не будет использоваться какой-либо другой сущностью, мы можем вложить его в класс Student, но эта более ранняя версия Entity Framework не поддерживает вложенные типы.

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

public class Student {
   public int ID { get; set; }
   public string LastName { get; set; }
   public string FirstMidName { get; set; }
	
   public DateTime EnrollmentDate { get; set; }
   public Person Identity { get; set; }
	
   public virtual ICollection<Enrollment> Enrollments { get; set; }

   public class Person {

      public Person(string fatherName, DateTime birthDate) {
         FatherName = fatherName;
         BirthDate = birthDate;
      }

      public string FatherName { get; set; }
      public DateTime BirthDate { get; set; }
   }
}

В Entity Framework 6 распознаются вложенные объекты и сложные типы. В приведенном выше коде вы можете видеть, что Person вложен в класс Student.

Когда вы используете Entity Framework Power Tool, чтобы показать, как Entity Framework интерпретирует модель в этот раз, есть истинное свойство Identity и комплексный тип Person. Таким образом, Entity Framework сохранит эти данные.

Тип вложенного объекта

Теперь вы можете видеть, что Identity является вложенным типом сущности, который не был поддержан до Entity Framework 6.

Мы рекомендуем вам выполнить вышеприведенный пример пошагово для лучшего понимания.