phdru.name / Russian / Software

Объектно-реляционные отображения. Их достоинства и недостатки.

Объектно-реляционное отображение (ORM = object-relational mapper) - это библиотека языка программирования, выполняющая отображение объектов реляционной модели (отношения, строки и атрибуты) на объекты языка программирования (классы, экземпляры, методы, атрибуты).

Таблица (отношение, включая виртуальные таблицы - JOIN, VIEW) обычно соответствуют классу, строки таблицы - экземплярам этого класса, колонки таблицы ("реляционные атрибуты") при этом отображаются на атрибуты объекта или вызовы методов чтения/записи. Отображение это обычно двунаправлено: манипуляции с атрибутами объекта приводят к чтению информации из (и записи в) соответствующие таблицы базы данных.

Могут также поддерживаться искусственные атрибуты (транслирующие значения в колонках таблицы во что-то более содержательное для прикладной задачи).

ORM управляется описанием отображения схемы БД на схему языка программирования. Например (все примеры даны на языке Python):

class Elephant(DBTable):
   table_name = "elephants"
   id = IntegerColumn(auto_increment=True, primary_key=True)
   color = StringColumn(default=None, length=30)

Этот класс описывает таблицу 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 и, возможно, обновляет кэш

Достоинства объектно-реляционных отображений.

Главных достоинств три. Во-первых, существует явное описание схемы БД в терминах языка программирования; описание это существует и изменяется в одном месте. Надо, скажем, добавить колонку в таблицу - выполняем ALTER TABLE ADD COLUMN (или ещё того лучше - поручаем нашему отображению выполнить такую команду), дописываем одну строку в описание схемы БД - ву-а-ля! - атрибут доступен для чтения и записи.

Достоинство номер два - программист манипулирует привычными элементами языка программирования - классами, объектами (экземплярами классов), атрибутами и методами.

Третье достоинство - автоматическая генерация SQL-запросов. Не надо писать DDL самому - ORM сгенерирует описание схемы. Не надо менять зашитые в программу DML-запросы при изменении схемы БД. Не надо менять запросы при переносе на другую СУБД - низкоуровневый драйвер ORM будет создавать новые запросы сам.

Недостатки.

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

Этот слой создаёт дополнительный уровень абстракции, через который подчас бывает необходимо продраться, чтобы понять, где, что и как в программе работает (или не работает). Необходимо разобраться, где обычные классы, методы и атрибуты, а где объекты ORM, вызывающие побочные эффекты (пишем значение в атрибут, а оно пишется ещё и в БД).

Эта абстракция отображает друг на друга не вполне совместимые (по своим операциям) парадигмы - объектно-ориентированную и реляционную. Какой, например, реляционной операции соответствует объектно-ориентированное наследование? Какой объектно-ориентированной операции соответствует соединение нескольки реляционных таблиц? Существуют разные способы преодоления этого impedance mismatch, но технические решения не снимают само различие этих моделей.

Дополнительный слой - это дополнительный код, который надо распространять вместе с программой; он вызывает увеличение объёма и падение скорости программы.

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

Коля Телегин добавляет: одна из типовых проблем с кэшированием - согласование изменений между разными сессиями.

Недостатки конкретных реализаций. Реализации ORM бывают сильно негибки. Они могут требовать своей собственной схемы БД, и могут не быть применены к базам данных, созданным другими средствами. Они могут генерировать ограниченный круг запросов (скажем, join не более чем по двум таблицам) и не позволяют написать SQL-запрос в явном виде, в результате чего эти запросы приходится давать непосредственно через драйвер базы данных; в этом случае в программе наступает кавардак из-за смешения стилей - объектно-реляционного и чисто реляционного.

Коля Телегин добавляет:

За:

-- позволяет отвязать код программы от деталей хранения данных: где и как хранятся значения атрибутов хранимых объектов. Схема, имена, сама БД может меняться. Процесс внесения изменений может быть организационно сложен.

Это решает как минимум следующие проблемы:

* в новых системах схема базы данных обычно уточняется постепенно, по мере продвижения разработки. Практики показывает, что это совершенно нормально, но в отсутствии чётко определённого уровня, отвечающего за трансляцию API<->storage, такие изменения очень дороги. ORM позволяет, как ты и говоришь, сконцентрировать эти изменения в одном месте. Реализация ORM с продуманной семантикой и достаточной инструментальной поддержкой делает такие изменения практически безболезненными.

* в существующих больших системах часто нужно собирать данные для одной сущности (объекта) из разных источников. ORM опять-таки позволяет эти детали локализовать в одном месте.

Много написано про impedance mismatch между процедурным кодом и SQL. Это как раз несовместимость парадигм, про которую ты упоминаешь. ORM как раз концентрирует эту несовместимость в явном виде и в одном месте. Это достоинство, а не недостаток. Отображение наследования и композиции на таблицы - вещь хорошо изученная, и развитыми ORM поддерживается.


Эта страница https://phdru.name/Russian/Software/orm.html была сгенерирована 14.07.2021 в 00:38:07 из шаблона CheetahTemplate orm.tmpl; Некоторые права зарезервированы. Вы можете узнать о технических аспектах этого сайта.