
Доклад по ORМ / ORM
.docОпределение
ORM (англ. Object-relational mapping), (русск. Объектно-реляционная проекция) — технология программирования, которая связывает базы данных с концепциями объектно-ориентированных языков программирования, создавая «виртуальную объектную базу данных».
Еще определение
Объектно-реляционное отображение (ORM = object-relational mapper) - это библиотека языка программирования, выполняющая отображение объектов реляционной модели (отношения, строки и атрибуты) на объекты языка программирования (классы, экземпляры, методы, атрибуты).
Таблица (отношение, включая виртуальные таблицы - JOIN, VIEW) обычно соответствуют классу, строки таблицы - экземплярам этого класса, колонки таблицы ("реляционные атрибуты") при этом отображаются на атрибуты объекта или вызовы методов чтения/записи. Отображение это обычно двунаправлено: манипуляции с атрибутами объекта приводят к чтению информации из (и записи в) соответствующие таблицы базы данных.
Зачем это нужно
В мире хранения данных доминируют реляционные СУБД, тогда как объектный подход к проектированию и программированию - в мире обработки данных.
Объектная и реляционная модели ортогональны. Это значит, что они моделируют одну и ту же сущность, но с разных сторон, под разными, я бы сказал перпендикулярными углами зрения. Реляционная модель акцентирует свое внимание на структуре и связях сущностей, объектная - на их свойствах и поведении. Цель использования реляционной модели - информационное моделирование, выделение существенных для нас атрибутов, сохранение их значений и последующего поиска, обработки и анализа. Цель использования объектной - моделирование поведения, выделение существенных для нас функций и последующего их использования. Между моделями есть пересечение - структурные сущности, которые по-разному в этих моделях отражаются. Для того, чтобы отобразить артефакты реляционной модели в артефакты же объектной в наших программах и требуется средство объектно-реляционной проекции - ОРП или широко распространенное англоязычное обозначение - ORM (Object Relational Mapping).
Выражаясь более простым языком, объектно-реляционный проектор - ОРП - теоретически позволяет программисту работать с таблицами, полями и связями реляционной БД, как с объектами, свойствами и коллекциями (массивами), не отвлекаясь на подробности более низкого уровня, такими, например, как порядок выборки и сохранения модифицированных данных, вопросы переносимости и особенностей диалекта SQL конкретной СУБД, генерации уникальных первичных ключей, заполнения полей ссылок для моделирования связей.
Из уже названных различий между целями использования реляционной и объектной моделей следует в частности, что если в вашей системе основной упор делается на многокритериальный поиск и массированное извлечение информации (класс информационно-поисковых систем, OLAP, генерация отчетности), то использование объектов для доступа к данным не является оправданным, а попросту излишне. Никакого различия между табличным представлением информации в базе данных, внутри вашей программы и на экране пользователя или в отчете нет, промежуточная обработка сводится к соединениям все тех таблиц и простым пересчетам значений их полей. Другое дело, если ваша система осуществляет транзакционную обработку (OLTP), сложные расчеты, оповещения о событиях, диспетчеризацию, моделирует поведение - здесь преимущества использования ОРП наибольшие.
Пример
Класс описывает таблицу elephants, в которой нас интересует одна колонка color
типа string. Для манипуляции с таблицей есть колонка id, являющаяся
целочисленным первичным ключом таблицы.
Мы можем создать новую строку в таблице:
elephant = Elephant.new() # Выполняет INSERT
и id будет назначен автоматически; поле color будет NULL. Или мы можем сразу занести данные:
elephant = Elephant.new(color="pink") # Выполняет INSERT
Мы можем извлечь существующую строку по id:
elephant = Elephant(id=2112)
или несколько строк поиском по цвету:
elephants = Elephant.select(color="pink")
В результате запроса в elephants окажется (возможно, пустой) список выбранных объектов.
Чтение атрибутов приводит к чтению данных (непосредственно из таблицы или из кэша):
color = elephant.color # Выполняет SELECT и, возможно, кэширует результат
Запись атрибутов приводит к записи информации в таблицу:
elephant.color = "pink" # Выполняет UPDATE и, возможно, обновляет кэш
Достоинства
-
Существует явное описание схемы БД в терминах языка программирования; описание это существует и изменяется в одном месте.
позволяет отвязать код программы от деталей хранения данных: где и как хранятся значения атрибутов хранимых объектов. Схема, имена, сама БД может меняться. Процесс внесения изменений может быть организационно сложен.
Это решает как минимум следующие проблемы:
* в новых системах схема базы данных обычно уточняется постепенно, по мере продвижения разработки. Практики показывает, что это совершенно нормально, но в отсутствии чётко определённого уровня, отвечающего за трансляцию API<->storage, такие изменения очень дороги. ORM позволяет, как ты и говоришь, сконцентрировать эти изменения в одном месте. Реализация ORM с продуманной семантикой и достаточной инструментальной поддержкой делает такие изменения практически безболезненными.
* в существующих больших системах часто нужно собирать данные для одной сущности (объекта) из разных источников. ORM опять-таки позволяет эти детали локализовать в одном месте.
-
Программист манипулирует привычными элементами языка программирования - классами, объектами (экземплярами классов), атрибутами и методами.
-
Автоматическая генерация SQL-запросов. Не надо писать DDL самому - ORM сгенерирует описание схемы. Не надо менять зашитые в программу DML-запросы при изменении схемы БД. Не надо менять запросы при переносе на другую СУБД - низкоуровневый драйвер ORM будет создавать новые запросы сам.
Недостатки.
-
Объектно-реляционное отображение создаёт дополнительный слой между программой и базой данных. Этот слой имеет свой собственный API, который необходимо изучить, а это дополнительная нагрузка на программиста.
-
Этот слой создаёт дополнительный уровень абстракции, через который подчас бывает необходимо продраться, чтобы понять, где, что и как в программе работает (или не работает). Необходимо разобраться, где обычные классы, методы и атрибуты, а где объекты ORM, вызывающие побочные эффекты (пишем значение в атрибут, а оно пишется ещё и в БД).
-
Эта абстракция отображает друг на друга не вполне совместимые (по своим операциям) парадигмы - объектно-ориентированную и реляционную.
Какой, например, реляционной операции соответствует объектно-ориентированное наследование? Какой объектно-ориентированной операции соответствует соединение нескольких реляционных таблиц? Существуют разные способы преодоления этого семантического разрыва, но технические решения не снимают само различие этих моделей.
-
Дополнительный слой - это дополнительный код, который надо распространять вместе с программой; он вызывает увеличение объёма и падение скорости программы.
-
В случае ошибок в реализации ORM в программе возникают трудноотлаживаемые ошибки. Особенно тяжёлый случай - ошибки в реализации кэширования, когда ORM кэширует слишком мало, или наоборот, слишком агрессивно.
-
Недостатки конкретных реализаций.
Реализации ORM бывают сильно негибки. Они могут требовать своей собственной схемы БД, и могут не быть применены к базам данных, созданным другими средствами. Они могут генерировать ограниченный круг запросов (скажем, join не более чем по двум таблицам) и не позволяют написать SQL-запрос в явном виде, в результате чего эти запросы приходится давать непосредственно через драйвер базы данных; в этом случае в программе наступает кавардак из-за смешения стилей - объектно-реляционного и чисто реляционного.
Существующие решения
Название |
Производитель, сайт |
Лицензия |
Поддержка СУБД |
Hibernate/ NHibernate |
http://www.hibernate.org |
Свободно распространяемый, с открытым исходным кодом |
MS SQL Server, Oracle, DB2, Access, MySQL, PostgreSQL, SQLite, Firebird |
DataObjects.NET |
X-tensive, http://www.x-tensive.com/Products/DataObjects.NET/ |
Коммерческая, на разработчика |
MS SQL Server, Oracle, SAP DB, Firebird/Interbase |
eXpress Persistent Objects (XPO) |
Developer Express, http://www.devexpress.com/products/NET/XPO/ |
Коммерческая, на разработчика, исходный код доступен |
MS SQL Server, Access, MySQL, Oracle, Advanced Data Server, PostgreSQL |
LLBLGen Pro |
http://www.llblgen.com |
Коммерческая, на разработчика |
MS SQL Server, Access, Oracle, Firebird/Intervase, DB2, MySQL |
Versant Open Access .NET (VOA) |
Versant, http://www.versant.com/products/openaccess/dotnet |
Коммерческая, на разработчика |
MS SQL Server, Oracle, FastObjects |
Hibernate (Java)/ NHibernate (.NET)
NHibernate является перенесенной на платформу .NET версией ОРП Hibernate для Java. Несомненным плюсом является зрелость своего Java-собрата по части концепций, архитектуры и алгоритмов, который с другой стороны является и минусом: "лобовой" перенос неоптимален, значит, часть кода переписывается с учетом специфики .NET, что означает новые ошибки и обычные проблемы "детского возраста". Версия для .NET по естественным причинам также обречена отставать от своего Java-аналога (в настоящее время .NET аналог соответствует версии 2.0.3, тогда как Java-разработчикам уже доступна версия 3). Поддерживается прямой и обратный инжиниринг, правда, только в ручном режиме.
В качестве недостатков следует отметить незрелость продукта, которая проявляется в скудной документации (рекомендуется читать ее полную версию для Java-аналога), плохой поддержке, отсутствии четкой и стабильной методики разработки. Весь опыт и "база знаний" пока концентрируются в нескольких разбросанных по сети статьях разработчиков, использовавших NHibernate, и паре не вполне наглядных примеров. Создание тестового приложения напоминало постоянное "хождение по граблям", при этом найти решение очередной проблемы занимало большое количество времени (многие часы поисков в сети). Никаких средств моделирования не поставляется, но в дополнительном пакете (contribution) есть утилита командной строки, которая по XML-файлу описания отображения генерирует либо схему БД, либо слой прикладных объектов.
Нельзя обойти вниманием и очевидные достоинства продукта: полный спектр поддерживаемых СУБД, язык запросов. близкий к SQL по синтаксису, отсутствие необходимости наследования от общего предка, четкое разделение кода, схемы отображения и схемы БД. Например, если вы уже имеете иерархию классов, то для отображения ее на базу данных вам не придется что-то в них изменять: NHibernate аккуратно сопоставит схему отображения с вашими классами и сохранит их в БД. При этом код уровня IL также остается нетронутым. NHibernate также отлично справляется с задачей генерации уникальных идентификаторов объектов: алгоритм (их доступно несколько) задается на уровне описания, разработчику не нужно ничего дополнительно программировать. По моему мнению, NHibernate имеет хороший потенциал для развития и через год может стать одним из лидеров рынка.
DataObjects.NET
Приятно увидеть в этом ряду продукцию отечественного производителя. ОРП поддерживает прямую и обратную разработку и весьма интересные дополнительные возможности, такие как полнотекстовый поиск (на основе MS Search для MS SQL Server или DotLucene - независимой от конкретной СУБД системы), систему безопасности схожую по принципам с NTFS, возможность выгрузки в т.н. offline layer - временное хранилище для обеспечения работы приложения вне сети с последующей синхронизацией, версионность объектов, поддержка более одного языка для значений атрибутов. Документация достаточно полная, однако презентация из 140 слайдов, которая рассчитана по словам самих разработчиков на 2 часа просмотра вряд ли может быть названа удачной находкой. Продукт нельзя отнести только к классу ОРП: по причине широкого функционала он ближе к каркасу разработки корпоративных приложений. Соответственно, если ваша задача умещается в рамки ОРП, то фреймворк такого уровня может оказаться излишне "тяжелым". Также в руководстве ничего не удалось найти на тему интеграции с CASE и UML.
eXpress Persistent Objects (XPO)
Компания Developer Express давно известна своим великолепным набором визуальных компонентов (eXtra grid, eXtra reports...) для сред Delphi и .NET. XPO в этом ряду выглядят не менее привлекательно. Продукт оставляет ощущение легкости, но не легковесности. Документация достаточна при своем небольшом объеме, порог вхождения для новичка низок, в поставку входит множество примеров. Интеграция с Visual Studio на уровне шаблонов и дизайнеров для компонентов. Схему проекции можно задавать как непосредственно в метаданных классов, так и в отдельном XML-файле, обеспечивая тем самым, использование одного и того же набора классов для работы с разными СУБД. Возможность проекции на хранимые процедуры (атрибуты отображаются на параметры) анонсирована в версии 2 (актуальная версия имеет номер 1.6), которая, однако, не спешит появится на свет.
Кроме функций ОРП реализована поддержка логического удаления объектов по принципу "мусорной корзины" с возможностью их восстановления. Хочется отметить хорошую поддержку как в новостной группе devexpress.public.dotnet.xpo на сервере компании news.devexpress.com, так и на форуме. Имеется обширная база знаний, на сайте опубликован ряд статей, освещающих рекомендуемые методы решения часто встречающихся ситуаций и проблем. Коллекции объектов без каких-либо ограничений подключаются как к стандартным сеткам (grids) в .NET, так и к собственным eXtra grids. Мое субъективное мнение об XPO благоприятное: с помощью документации и базы знаний прототип был собран за несколько часов, в то время как аналогичная работа для NHibernate заняла три дня, оставив больше вопросов, чем ответов. К числу недостатков можно отнести отсутствие готовых средств моделирования или интеграции с CASE, необходимость модификации БД (вручную или автоматически добавляются 2 служебные таблицы и по 2 поля в каждую таблицу). Неудачным решением мне кажется отсутствие языка запросов, условия выборки (where) конструируются путем создания массива объектов-выражений и связок.
LLBLGen Pro
Продукт рассчитан в большей степени на обратный инжиниринг. Даже если вы создаете новое приложение, то рекомендуется начать процесс с проектирования базы данных, затем генератор создает вам слой прикладных объектов. В дальнейшем, вы сможете вносить изменения уже на уровне объектной модели: для этого разработчику предоставляется графический интерфейс, в котором он может добавлять/модифицировать элементы и управлять отображением (mapping). Продукт фактически создается и поддерживается единственным голландским разработчиком, в этом есть и плюсы: максимальное качество ответов на вопросы, единая непротиворечивая архитектура, так и минусы: риски остаться наедине с продуктом, если автор потеряет к нему интерес. Успешная истории использования LLBLGen нашими партнерами из Firstream (http://www.firstream.com) в достаточно большом проекте (портал финансовых транзакций типа WebMoney с широкими возможностями персонификации, 1,3 млн. клиентов, решение целиком создано на платформе Microsoft: ASP.NET, WebServices, MS SQL Server) позволяет утверждать, что продукт готов для промышленного использования в OLTP-приложениях. Интеграция с CASE отсутствует, имеется собственный интерфейс моделирования, отображающий артефакты в виде древовидных структур, что не всегда удобно по сравнению с диаграммой классов.
Versant Open Access .NET (VOA)
Этот продукт также является переносом на платформу .NET своей одноименной Java-версии. Поддерживается прямой и обратный инжиниринг. Хорошо интегрированный с Visual Studio, он позволяет визуально управлять (mapping designer) отображением и генерацией/модификацией схемы БД прямо из среды, однако, сами прикладные классы необходимо либо изначально писать вручную, либо генерировать из вашего любимого CASE, либо генерировать с помощью самого VOA на основе существующей базы данных.
К числу недостатков следует отнести небольшой спектр поддерживаемых СУБД, проблемы с управлением генерацией уникальных идентификаторов объектов (не поддерживается GUID), модификация кода ваших объектов на IL-уровне. Тем не менее, продукт активно развивается, на сайте опубликованы планы по устранению проблем в новой версии до конца этого года, но уже для платформы .NET 2.