Что такое entity framework c
Перейти к содержимому

Что такое entity framework c

  • автор:

Работа с Entity Framework 6

является продолжением технологии Microsoft ActiveX Data и предоставляет возможность работы с базами данных через объектно-ориентированный код C#. Этот подход предоставляет ряд существенных преимуществ: вам не нужно беспокоиться о коде доступа к данным, вам не нужно знать деталей работы СУБД SQL Server и синтаксиса языка запросов T-SQL, вместо этого вы работаете с таблицами базы данных как с классами C#, с полями этих таблиц — как со свойствами классов, а синтаксис SQL-запросов, который в ADO.NET раньше нужно было вставлять в код C# в виде команд, заменен на более удобный подход с LINQ. Entity Framework берет на себя обязанности по преобразованию кода C# в SQL-инструкции.

При работе с Entity Framework вам предоставляются огромные возможности по созданию модели базы данных с помощью интегрированной среды разработки (IDE) Visual Studio. Начиная с версии Entity Framework 4.1 вам предоставляется три подхода по проектированию базы данных, из которых вы можете выбрать для себя подходящий:

Database-First

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

Model-First

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

Code-First

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

Лично я при работе с Entity Framework выбираю подход Code-First, но в нашем руководстве мы рассмотрим все три подхода.

1. Знакомство с Entity Framework

  1. Развитие Entity Framework
  2. Простое приложение с использованием Entity Framework
  3. Подходы для работы с Entity Framework
  4. Использование Code-First
  5. Использование Model-First
  6. Использование Database-First

2. Code-First: аннотации и Fluent API

  1. Настройка столбцов таблицы
  2. Создание связи между таблицами
  3. Каскадное удаление данных
  4. Отношение один-к-одному (one-to-one) между таблицами
  5. Отношение многие-ко-многим (many-to-many) между таблицами
  6. Настройка схемы и таблиц базы данных
  7. Множественные сущности и таблицы
  8. Настройка привязки модели к базе данных
  9. Настройка подключения к базе данных
  10. Создание базы данных
  11. Миграции модели данных в Code-First
  12. Расширенные возможности настройки Code-First

3. Работа с данными

  1. Описание DbContext API
  2. Создание запросов
  3. Загрузка данных
  4. Загрузка связанных данных
  5. Вставка данных
  6. Обновление данных
  7. Удаление данных
  8. Уведомления о изменениях данных

Введение в Entity Framework

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

Первая версия Entity Framework — 1.0 вышла еще в 2008 году и представляла очень ограниченную функциональность, базовую поддержку ORM (object-relational mapping — отображения данных на реальные объекты) и один единственный подход к взаимодействию с бд — Database First. С выходом версии 4.0 в 2010 году многое изменилось — с этого времени Entity Framework стал рекомендуемой технологией для доступа к данным, а в сам фреймворк были введены новые возможности взаимодействия с бд — подходы Model First и Code First.

Дополнительные улучшения функционала последовали с выходом версии 5.0 в 2012 году. И наконец, в 2013 году был выпущен Entity Framework 6.0, обладающий возможностью асинхронного доступа к данным.

Центральной концепцией Entity Framework является понятие сущности или entity. Сущность представляет набор данных, ассоциированных с определенным объектом. Поэтому данная технология предполагает работу не с таблицами, а с объектами и их наборами.

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

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

Отличительной чертой Entity Framework является использование запросов LINQ для выборки данных из БД. С помощью LINQ мы можем не только извлекать определенные строки, хранящие объекты, из бд, но и получать объекты, связанные различными ассоциативными связями.

Другим ключевым понятием является Entity Data Model . Эта модель сопоставляет классы сущностей с реальными таблицами в БД.

Entity Data Model состоит из трех уровней: концептуального, уровень хранилища и уровень сопоставления (маппинга).

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

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

Уровень сопоставления (маппинга) служит посредником между предыдущими двумя, определяя сопоставление между свойствами класса сущности и столбцами таблиц.

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

Способы взаимодействия с БД

Entity Framework предполагает три возможных способа взаимодействия с базой данных:

  • Database first : Entity Framework создает набор классов, которые отражают модель конкретной базы данных
  • Model first : сначала разработчик создает модель базы данных, по которой затем Entity Framework создает реальную базу данных на сервере.
  • Code first : разработчик создает класс модели данных, которые будут храниться в бд, а затем Entity Framework по этой модели генерирует базу данных и ее таблицы

Entity Framework Core

Привет, друзья. В этот чудесный майский день мы продолжаем трудиться и сегодня хотим рассказать о том, что в мае OTUS запускает полюбившийся всем курс «Разработчик С#», а также отдельный курс по С# ASP. NET Core. Традиционно, в преддверии старта курсов начинаем публиковать полезный материал. Поехали.

Вступление

В большинстве современных ASP NET Core приложений используется Entity Framework Core. Entity Framework Core – это технология для доступа к базам данных от Microsoft. Оно позволяет взаимодействовать с СУБД с помощью сущностей (entity), то есть классов и объектов NET, а не таблиц базы данных. Это самый известный и функциональный ORM – инструмент в C#. ORM — это object-relational mapping — отображение данных на реальные объекты.

Например, если разработчик напрямую работает с базами данных, программист должен думать о подключении, подготовке SQL и параметров SQL, как отправлять запросы и о транзакциях. А с помощью Entity Framework Core все это делается автоматически — разработчик работает непосредственно с классами NET.

Подходы ORM

У ORM есть несколько подходов.

Первый – Code First. Он подразумевает, что сначала пишется код на C#, а потом по этому коду создается база данных. Для этого подхода очень важно определить классы модели или entity, которая будет храниться в базе данных, описать ее в классах C# в виде модели, и написать класс контекста, который и будет работать с используемой базой данных. Подход Code First используется чаще всего программистами C#.

Второй подход — Database-First- подходит для тех, кто хорошо знает SQL, но в этом случае необязательно хорошо знать C#. Первым делом создается база данных, затем генерируется EDMX-модель базы данных. В этом XML в файле .edmx содержится информация о структуре базы, модель данных и маппинг их друг на друга. В Visual Studio есть графический дизайнер, с помощью которого можно работать с .edmx

Model-First – это третий подход ORM. Его часто используют архитекторы, так как при этом подходе можно не знать ни SQL, ни синтаксис C#. В этом случае сначала создается графическая модель EDMX, в это время в фоновом режиме создаются классы C# модели, а затем генерируется база данных на основе диаграммы EDMX.

Модели Entity Framework Core

Все таблицы базы данных определяются в Entity Framework в виде классов моделей или сущностей (entity), как правило, по принципу 1 таблица, например users, – 1 класс в NET, например, User. Такие пары называют условностями, и они определены в классе контекста данных как наборы DbSet и такой подход работает по умолчанию.

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

Миграции

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

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

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

LINQ

С Entity Framework в NET неразрывно связан и LINQ. LINQ — это Language Integrated Query или Внутриязыковой запрос — это такая технология, которая представляет собой набор функций в NET, которые позволяют писать структурированные запросы к базе данных.

Для работы с Entity Framework Core использует технологию LINQ to Entities. LINQ использует похожие на SQL выражения языка C# для получения данных из базы данных. Любая реляционная база данных работает через запросы на языке SQL, и Entity Framework Core выражения LINQ to Entities транслирует в запросы SQL, которые понятны для используемой базы данных.

Заключение

Таким образом мы кратко пробежались по возможностям Entity Framework Core. Как вы увидели, он действительно очень мощный, причем настолько, что программисту, который с ним работает даже не обязательно знать SQL. И Entity Framework Core по праву принадлежит первое место среди ORM в мире NET.

  • Записаться на бесплатный урок по теме: «Валидация данных на C#»
  • ASP.NET Core: быстрый старт

Entity Framework Core и высокая производительность

Entity Framework Core является рекомендованным и самым популярным средством взаимодействия с реляционными базами данных на платформе ASP NET Core. Это мощный инструмент который подходит для большинства сценариев, но, как и любой другой инструмент имеет свои ограничения. Долгое время бытовало мнение (и не безосновательно) что Entity Framework не подходит для высоконагруженных систем и в таких сценариях лучше использовать Dapper. Но время идет и Entity Framework развивается, в том числе в плане оптимизации. Помимо улучшения производительности самой платформы .NET, Entity Framework Core для NET 6 имеет ряд настроек и возможностей, призванных значительно улучшить производительность. В этой статье мы рассмотрим Entity Framework Core с точки зрения производительности и сравним его с Dapper используя актуальные версии на момент июля 2022 года. Посмотрим насколько рекомендация «перепишите все на Dapper» актуальна 🙂

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

Введение в EF

Перед углублением в тему производительности было бы полезно вспомнить что такое EF и описать некоторые аспекты его работы, которые помогут нам в понимании разных подходов к оптимизации. Итак, EF это object-relational mapper (ORM) или инструмент, связывающий объектную модель, с которой мы работаем в коде (C# классы, коллекции, свойства) с реляционной моделью базы данных (таблица, столбец, запись, связи etc). Основной объект, который предоставляет EF для работы с базой данных это класс производный от DbContext . Класс содержит в себе набор объектов-коллекций DbSet , которые чаще всего соотносятся с таблицами базы данных. Для доступа к этим данным, мы обращаемся к этим коллекциям с помощью LINQ запросов, которые за кадром транслируются в SQL при вызове методов ToArray , ToList , FirstOrDefault и т.д., и работаем с данными также, как и с обычными C# объектами.

public class AdventureWorksContext : DbContext < public virtual DbSetProducts < get; set; >. > . public void ApplicationLogic() < using var context = new AdventureWorksContext(); // get list of products with filter var bookProducts = context.Products.Where(p =>p.Type == "Book").ToList(); // get single product by name var singleBook = context.Products.Where(p => p.Name == "Harry Potter").FirstOrDefault(); // do data handling . >

То, как работает, EF дает разработчикам несколько преимуществ. Во-первых, EF берет на себя ответственность за формирование корректных и безопасных от SQL инъекций запросов к базе данных для конкретного провайдера, используя строго типизированные LINQ запросы. Один и тот же C# код будет работать с MSSQL, Oracle и MySQL. Разработчик в большинстве случаев полностью абстрагируется от работы с SQL синтаксисом и может сосредоточиться на логике приложения. Во-вторых, EF предоставляет механизм, который отслеживает изменения свойств объектов (change-tracking) и позволяет при фиксации формировать Update и Delete запросы в базу данных, также без написания разработчиком какого либо SQL кода. Например:

public void ApplicationLogic() < using var context = new AdventureWorksContext(); var bookProduct = context.Products.Where(p =>p.Name == "Harry Potter").Single(); bookProduct.Name = "Harry Potter and the Sorcerer's Stone" context.SaveChanges(); // name in DB was updated ! context.Remove(bookProduct); context.SaveChanges(); // book was deleted from DB ! . >

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

  1. Получение экземпляра DbContext . Для начала нам необходимо получить экземпляр DbContext , который содержит все что необходимо для работы.
  2. Компиляция LINQ запроса в SQL. Реализация интерфейса IQueryable , которую мы получаем вызывая методы расширения LINQ на DbSet , представляет из себя объект запроса, который предстоит выполнить. Объект строится по принципу builder-а: каждый вызванный метод Where , OrderBy , Select и т.д. добавляет в объект запроса новую информацию, которая позже будет транслирована в SQL. IQueryable наследуется от IEnumerable , но до тех пор, пока вы не вызвали методы IEnumerable (или IAsyncEnumerable ) явно — SQL запрос не будет сформирован и отправлен в базу. При вызове на IQueryable объекте метода, явно приводящего запрос к IEnumerable (или IAsyncEnumerable ), такого как ToArray , ToList , FirstOrDefault и т.д. запускается процесс трансляции. EF транслирует объект IQueryable в SQL, при этом поддерживая внутренний кэш, который позволяет переиспользовать результаты трансляции для одинаковых LINQ запросов и не проводить тяжелые вычисления повторно.
  3. Отправка SQL запроса в базу данных и получение ответа (server-side calculations).
  4. Материализация результатов запроса в C# объекты.
  5. Регистрация объектов в системе отслеживания изменений (change-tracking). После того как произошла материализация объектов, EF по умолчанию регистрирует эти объекты во внутренней системе отслеживания изменений, которая отслеживает изменения свойств объекта и при вызове SaveChanges формирует соответствующий Update запрос в базу данных. На поддержание системы отслеживания изменений и информации которая в ней хранится также тратятся ресурсы.
  6. Выполнение клиентской части LINQ запроса (client-side calculations). Получая LINQ запрос EF пытается трансформировать его в SQL чтобы он был выполнен на сервере базы данных (server-side calculation). Но в некоторых случаях он не может этого сделать, и тогда выражение должно быть рассчитано на клиенте, после того как все что удалось трансформировать в SQL выполнится на сервере. В ранних версиях EF Core программист мог узнать о том что EF не смог трансформировать часть запроса в SQL и она была неявно выполнена на клиенте только из логов, или специально настроив выброс исключений в подобных случаях, однако в последних версиях, при невозможности конвертировать LINQ в SQL EF всегда будет выбрасывать исключение, требуя явного вызова методов AsEnumerable , ToList и т.д. перед частью, которая может быть рассчитана только в C# (client-side calculations). Более подробно это описано в этой статье Microsoft. В интересах разработчика чтобы как можно больше вычислений, в особенности в блоке Where , происходили на стороне SQL сервера.
  7. Получение объектов вызывающим кодом.

Как видим между созданием DbContext , вызовом ADO NET и получением результатов в коде выполняется множество операций, которые потребляют ресурс процессора, создают объекты и сохраняют ссылки на них, нагружая GC, заполняют и очищают внутренние кэши и т.д. Dapper в свою очередь представляет собой минимальную прослойку между ADO NET и клиентским кодом, лишенную всех преимуществ EF, но от этого имеющую значительное преимущество по производительности. Для наглядности приведем пример кода с использованием Dapper:

public void ApplicationLogic() < using var sqlConnection = new SqlConnection(connectionString); var product = connection.QuerySingleOrDefault(@" select * from Products where Name = @name ", new < name = "Harry Potter" >); >

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

System Under Test (SUT)

Для демонстрации и сравнения нам понадобится веб API, которое будет взаимодействовать с тестовой SQL базой AdventureWorks, реализуя несколько часто встречающихся сценариев:

  • GET запрос по Id с данными из одной таблицы. Get product by Id;
  • GET запрос по Id с данными из нескольких связанных таблиц (JOIN-s). Get product with model and product category by id;
  • GET запрос страницы с данными из одной таблицы. Get products page;
  • GET запрос страницы с данными из нескольких связанных таблиц (JOIN-s). Get products page with model and product category datas;
  • POST запрос на создание. Create product
  • PUT запрос на редактирование. Edit product name.

Нам понадобится реализовать API несколько раз, используя разные имплементации IProductsRepository на базе EF или Dapper для доступа к данным. Для полноценного нагрузочного тестирования мы будем использовать NBomber поочередно для всех перечисленных сценариев. Подробнее о NBomber и работе с ним можно ознакомится в этой статье. Для более быстрых локальных тестов в некоторых случаях мы будем использовать BenchmarkDotNet сценарии, которые будут повторять наше API в миниатюре, вызывая разные реализации интерфейса IProductsRepository для EF, Dapper и вариаций EF с различными улучшениями:

private ServiceProvider EFCoreDefaultImplementationServiceProvider; . [GlobalSetup] public void GlobalSetup() < BuildDefaultImplementationServiceProvider(); >. [Benchmark] public async Task GetProduct_Benchmark() < // we will do several iterations, emulating several requests, to see difference in time and memory better for (int i = 0; i < IterationsCount; i++) < // as for each HTTP request in web api, we will create DI scope using var scope = EFCoreDefaultImplementationServiceProvider.CreateScope(); // . from which we will resolve implementation under test var repository = scope.ServiceProvider.GetRequiredService(); // get product by id scenario as example var product = await repository.GetProduct(ProductIds[i % (ProductIds.Length - 1)]); > >

После того как мы рассмотрим все рекомендации по улучшению производительности работы EF, мы проведем еще один NBomber тест с примененными улучшениями и после сможем сделать выводы. Весь код использованный в данной статье доступен в репозитории на Github.

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

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *