Одна из проблем использования языков объектно-ориентированного программирования (ООП) и баз данных в сложности их согласования между собой. Знание языка структурированных запросов (SQL) и умение писать запросы позволяют взаимодействовать с БД напрямую. Но использование «чистого» SQL может занять довольно много времени, предъявляя повышенные требования к навыкам специалиста.
Облегчить рабочий процесс может объектно-реляционное отображение (ORM). Сторонники этой технологии заявляют, что она повышает производительность, улучшает архитектуру приложений, повторно использует код и поддерживает приложение с течением времени. По мнению критиков, отрицательным аспектом ORM является производительность.
В этой статье наше backend-направление расскажет про ORM на базе C#, плюсы и минусы этой технологии, чтобы оценить ее полезность при разработке приложений. Материал предназначен для разработчиков, желающих погрузиться в принципы подбора ORM.
Что такое ORM?
ORM — это технология программирования, которая создает слой между реляционными базами данных и объектно-ориентированными языками программирования без необходимости написания SQL-запросов.
Отображение стандартизирует интерфейсы, сокращая количество шаблонов и ускоряя время разработки.
Технология преобразует множество состояний и кодов, создавая структурированную карту, которая помогает разработчикам лучше ориентироваться в структуре базы данных.
Отображение объясняет, как объекты связаны с разными таблицами, используя эту информацию для преображения данных между ними. ORM генерирует код SQL для реляционной базы данных (вставка, обновление, создание и удаления данных) в ответ на изменения, которые приложение вносит в объект данных. Сопоставление ORM будет управлять потребностями приложения в данных, избавляя от написания низкоуровневого кода.
Как работает ОRМ?
ORM выстраивает модели объектно-ориентированной программы с высоким уровнем абстракции. Другими словами, она создает уровень логики без основных деталей кода. Отображение описывает отношения между объектом и данными, не зная, как эти данные структурированы. Далее модель можно использовать для подключения приложения к коду SQL, который необходим для управления операциями с данными. Этот «сантехнический» тип кода не нужно переписывать, что значительно экономит время разработки.
Типы ORM
ORM используют две разные стратегии: шаблон активной записи и шаблон отображения данных.
Шаблон активной записи (Active record). Эта стратегия сопоставляет данные со структурой объектов в коде. Разработчик управляет данными, используя классы и структуры. У этого метода есть проблемы, поскольку структура базы данных тесно связана с кодом, это затрудняет удаление базы данных и перенос ее в другое приложение.
Шаблоны отображения данных. Шаблон разделяет бизнес-логику и БД в объектах. В результате становится проще изменять базы данных и использовать одну и ту же логику программирования.
Плюсы и минусы ORM
ORM избавляет разработчиков от написания большого количества кода и необходимости работы с SQL, как правило, однообразного и подверженного ошибкам. Весь генерируемый ORM код выверен и оптимизирован, поэтому в целом не требует дополнительного тестирования.
К основным минусам можно отнести потерю производительности. Большинство ORM обрабатывают гораздо больше сценариев использования данных, чем нужно каждому отдельному приложению.
Чаще вопрос о целесообразности использования ORM затрагивается в больших проектах с высокой нагрузкой. Конечно, работа с БД посредством грамотно написанного SQL-кода будет намного эффективнее, но не стоит забывать и о времени, которое может сэкономить вам ORM. Кроме того, большинство современных объектно-реляционных отображений позволяют разработчику при необходимости самому задавать код SQL-запросов. Без сомнений, для небольших проектов использование ORM более оправдано, чем разработка собственных библиотек для работы с БД.
Мы провели опрос среди разработчиков SimbirSoft и узнали, как часто они используют ORM на проектах. Вот что получилось:
В нашей команде ORM-системы довольно популярны и часто применяются на проектах: за них проголосовали 80,8%, против — 19,2%. Наши разработчики также отмечают, что ORM-системы эффективны в случаях, когда система не высоконагруженная и когда необходим быстрый запуск типового решения.
Обзор ORM
Итак, мы познакомились с общим понятием ORM-систем, принципом их работы, теперь рассмотрим некоторые из них более подробно.
Entity Framework (EF) — объектно-ориентированная технология доступа к данным, которая является object-relational mapping (ORM) решением для .NET Framework от Microsoft. Взаимодействует с объектами как посредством LINQ в виде LINQ to Entities, так и с использованием Entity SQL. Для облегчения построения web-решений используется ADO.NET Data Services, а также связка из Windows Communication Foundation (WCF) и Windows Presentation Foundation (WPF), которая позволяет строить многоуровневые приложения, реализуя один из шаблонов проектирования MVC, MVP или MVVM.
Часто разработчики критиковали EF из-за ее массивного объема, а также отмечали, что ядро EF не является кроссплатформенным. С .NET Core корпорация Майкрософт расширила доступность Entity Framework при помощи Entity Framework Core (EF Core). По их мнению, ядро EF — это легкая расширяемая кроссплатформенная версия популярной технологии доступа к данным Entity Framework с открытым исходным кодом. Одно из ключевых слов здесь — легкая. Все изменилось с EF Core, которая больше похожа на микро-ORM, чем ее предшественница. Ранее работоспособность и производительность .NET-приложений напрямую зависела от операционной системы Windows, но с .NET Core и EF Core это больше не является ограничением.
Если необходимо расширить код и сделать его более функциональным, то EF Core позволит это осуществить, благодаря открытому исходному коду и расширяемого ядра.
С EF Core, как и с другими ORM, разработчики могут использовать свои базы данных, включая объекты C#. Это отличная новость для тех, кому часто приходится писать весь необходимый код доступа к данным с нуля при работе на других языках.
Самостоятельное написание такого кода доступа к данным может оказаться сложной задачей. Реляционные БД отображают информацию в виде таблиц, например, электронных. Объектно-ориентированные языки, такие как C#, представляют свои данные в виде графиков.
Часто отладить работу кода и данных бывает затруднительно. Отсюда и необходимость в ORM. Такие инструменты, как EF Core, берут модель данных, состоящую из объектов C#, и преобразуют ее в реляционную форму, отражающую схему реляционной БД.
NHibernate — еще одна из наиболее широко используемых ORM для .NET, которая упрощает задачи, связанные с сохранением данных. Это не самое удачное решение для приложений, использующих только хранимые процедуры для реализации бизнес-логики в БД. Однако она наиболее полезна для объектно-ориентированных моделей предметной области и бизнес-логики в .NET среднего уровня. NHibernate может помочь удалить или инкапсулировать SQL-код конкретного поставщика, а также выполнить задачу преобразования набора результатов из табличного представления в график объектов.
Эта микро-ORM приобрела большую популярность и даже была включена в качестве опции ORM в Visual Studio при создании нового проекта. Одним из ее преимуществ является функциональность маппера, которая во многом похожа на LINQ в ядре EF, а также предоставляет методы расширения, упрощающие отправку операторов T-SQL в базу данных.
В науке микроуровни — это очень маленькие единицы мышления и коммуникации, а макроуровни — более крупные. Мезоуровни лежат где-то посередине.
Если Dapper — это микро-ORM, а EF — макро, то с архитектурной точки зрения LINQ to DB — это мезо-ORM. Она позволяет работать с выражениями LINQ в отличие от строк SQL или T-SQL, сохраняя при этом тонкий слой абстракции между кодом и базой данных. Запросы основаны на объектах и поэтому проверяются компилятором C#. LINQ to DB гораздо легче, чем LINQ для SQL или Entity Framework. В LINQ to DB нет отслеживания изменений, поэтому важно выявлять их самостоятельно. Однако эта ORM обеспечивает усиленный контроль и гораздо более быстрый доступ к данным — у Dapper он самый быстрый из всех ORM на основе LINQ.
Менее известная, но отличная микро-ORM, созданная разработчиком Джоном Вагнером специально для .NET и доступная в виде пакета NuGet. Она чрезвычайно быстрая, легкая, простая в реализации и использовании. Работает со всеми распространенными БД и может использовать либо хранимые процедуры, либо встроенный SQL.
Одной из ее значимых особенностей является реализация автоматического интерфейса.
Пример
Рассмотрим кейс одного из наших заказчиков, где бизнес-логика (БЛ) была написана на SQL. Со временем проект развивался и бизнес-логика разрасталась, многократно усложнялась — появилось множество нюансов, разновидностей, особенностей поведения сущностей и др. В результате к началу совместной работы БЛ стала практически неподдерживаемой, так как SQL — упрощенный язык, там нет возможностей для ООП. В проекте гибкая бизнес-логика имела большее значение, чем быстродействие системы. С учетом этого мы решили постепенно переписывать бизнес-логику на C# + Entity Framework (EF).
Иногда ORM может показаться огромной неповоротливой машиной. А если использовать методы-расширители, то возникает ощущение неполноты (меньше кода, чем в той же EF).
Рассмотрим пример с обновлением ID пользователя. В первом случае обновление умещается в 1 строку кода.
("update users set Archived = 1 where userId = '" + userID + "'").ExecuteNonQuery()
В Entity нужно создать контекст, заложить операцию, далее уничтожить контекст (но это лучше делать через using). Кроме того, нужно учитывать все, что находится в ChangeTracker:
using (var db = new DataContext()) {
var u = db.users.First(p=>p.userId = userId)
u.IsArchived = 1
db.saveChanges()
}
Заключение
Выбор ORM зависит от сложности используемых систем и реализуемого приложения. Среди .Net-разработчиков в нашей команде наиболее популярна Entity Framework благодаря удобству в использовании, а также обширной документации.
ORM-системы позволяют ускорить разработку, улучшить читаемость кода и его эстетическую сторону, но каждый инструмент следует применять только там, где это действительно необходимо.
Спасибо за внимание! Надеемся, что наш опыт вам пригодится.
Полезные материалы для разработчиков мы также публикуем в наших соцсетях - ВК и Telegram.
Комментарии (7)
Evengard
08.04.2022 14:16+3Касательно LinqToDb - во-первых, у них есть адаптер к EF Core - можно пользоваться полностью их движком запросов и всеми его возможностями, используя модели EF (включая EF-ные миграции, и вообще полностью DbContext из EFCore) - и даже используя EF-ный Change Tracker, если зачем-то нужно. Я в своих проектах использую EFCore и LinqToDb через этот адаптер к EF Core наравне, и нарадоваться не могу, воспринимая LinqToDb в таком режиме как возможность расширить достаточно куцый транслятор EFCore-linq выражений в SQL.
Во-вторых, разработчики LinqToDb вроде где-то были тут на Хабре.
ColdPhoenix
08.04.2022 14:32Рассмотрим пример с обновлением ID пользователя
надеюсь это не реальный код, судя по кавычкам там может быть строка, это не безопасно(привет sql-инъекции)
Лично я использую в ASP.Net Core проектах EFCore + FlexLabs.EntityFrameworkCore.Upsert при необходимости. В других проектах использовал Dapper в основном.
ArchitectSimbirSoft Автор
08.04.2022 15:11Уточним, что в этом примере идентификатор пользователя - GUID, поэтому атака SQL инъекцией невозможна
ColdPhoenix
08.04.2022 17:58+3А потом стандартный дотнетовский GUID не устраивает, начинаете его генерировать как строку, где-то забыли проверить и все, привет потенциальная уязвимость.
потому лучше делать грамотно, тем более когда это ничего не стоит в данном примере.
Так же при использовании параметров это уже будет параметризованный запрос, и некоторые бэкенды их могут преобразовать в prepared-statement.
JordanCpp
08.04.2022 17:20+1Знание ORM = знание sql + фич бд на проекте + знание и тонкости используемой orm. И в какой sql код, будет преобразован orm код. Не думаю, что следует привязывать бизнес логику к ORM'у. Следует привязывать к сервисам, а уже методы сервисов вызывать на уровне бизнес логики. Абстрагировать уровень бд. И уже все равно, что лежит в Service просто юзаем методы. Была неплохая статья на Хабре, типа я не буду учить +100500 ORM
IvaYan
А геодезист есть?
ArchitectSimbirSoft Автор
Спасибо за уточнение, речь о маппере, конечно же, поправили