Является ли функционал для реляционного сопоставления проще, чем Object to Relational?

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

Если используется функциональный язык, возникает ли та же проблема? Мне кажется, что эти две парадигмы должны сочетаться лучше, чем OO и RDBMS. Идея думать в наборах в РСУБД, похоже, сводится к автоматическому parallelism, что функциональные подходы, похоже, обещают.

Есть ли у кого-нибудь интересные мнения или идеи? Какое состояние игры в отрасли?

Ответ 1

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

Ответ 2

Какова цель ОРМ?

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

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

Как SQL может решить проблемы, возникающие у нас с ORM?

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

  • Oracle (возможно, самая сложная реализация)
  • PostgreSQL (в некоторой степени)
  • Informix
  • SQL Server, MySQL и т.д. (Через "эмуляцию" через XML или JSON)

По моему мнению, если бы во всех базах данных был реализован стандартный оператор SQL MULTISET() (например, в Oracle), люди больше не использовали бы ORM для отображения (возможно, все еще для сохранения графов объектов), потому что они могли материализовать вложенные коллекции непосредственно из баз данных, например, этот запрос:

SELECT actor_id, first_name, last_name,
  MULTISET (
    SELECT film_id, title
    FROM film AS f
    JOIN film_actor AS fa USING (film_id)
    WHERE fa.actor_id = a.actor_id
  ) AS films
FROM actor AS a

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

Функциональная парадигма на стороне клиента

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

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

Пример на Java с использованием jOOQ из этого поста в блоге может быть:

// Higher order, SQL query producing function:
public static ResultQuery<Record2<String, String>> actors(Function<Actor, Condition> p) {
    return ctx.select(ACTOR.FIRST_NAME, ACTOR.LAST_NAME)
              .from(ACTOR)
              .where(p.apply(ACTOR)));
}

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

// Get only actors whose first name starts with "A"
for (Record rec : actors(a -> a.FIRST_NAME.like("A%")))
    System.out.println(rec);

FRM абстракция над SQL

Некоторые FRM пытаются абстрагироваться от языка SQL, обычно по этим причинам:

  • Они утверждают, что SQL не является достаточно компостируемым (jOOQ это опровергает, просто очень трудно понять, как правильно).
  • Они утверждают, что пользователи API более привыкли к "нативным" API-интерфейсам коллекции, поэтому, например, JOIN переводится в flatMap() а WHERE - в filter() и т.д.

Ответить на ваш вопрос

FRM не "проще", чем ORM, он решает другую проблему. На самом деле FRM вообще не решает никаких проблем, потому что SQL, сам по себе являющийся декларативным языком программирования (который ничем не отличается от функционального программирования), очень хорошо подходит для других функциональных языков программирования клиента. Таким образом, FRM просто устраняет разрыв между SQL, внешним DSL и языком вашего клиента.

(Я работаю в компании за jOOQ, поэтому этот ответ предвзят)

Ответ 3

Это зависит от ваших потребностей.

  • Если вы хотите сосредоточиться на структурах данных, используйте ORM, например JPA/Hibernate
  • Если вы хотите пролить свет на лечение, посмотрите библиотеки FRM: QueryDSL или Jooq
  • Если вам нужно настроить SQL-запросы на определенные базы данных, используйте JDBC и собственные SQL-запросы

Эффективность различных технологий "Реляционное сопоставление" - мобильность: вы гарантируете, что ваше приложение будет работать на большинстве баз данных ACID. В противном случае вы сможете справиться с различиями между различными диалектами SQL при написании запросов SQL вручную.

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

Силы ORM создаются поверх объекта сеанса, который может действовать как узкое место:

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

Тем не менее, его сильные стороны также являются его недостатками:

  • Сессия должна иметь возможность сравнивать объекты, поэтому вам необходимо реализовать методы equals/hashCode. Но равенство объектов должно основываться на "Бизнес-ключах", а не на идентификаторе базы данных (новые транзиторные объекты не имеют идентификатора базы данных!). Однако некоторые овеществленные понятия не имеют делового равенства (например, операция). Общее обходное решение основывается на GUID, которые склонны нарушать администраторы баз данных.

  • Сессия должна отслеживать изменения связей, но ее правила сопоставления используют использование сборников, непригодных для бизнес-алгоритмов. Иногда вы хотели бы использовать HashMap, но ORM потребует, чтобы ключ был другим "Rich Object Object" вместо другого легкого... Затем вам нужно реализовать равенство объектов на объекте rich domain, действующем как ключ... Но вы не можете, потому что этот объект не имеет аналогов в мире бизнеса. Таким образом, вы возвращаетесь к простому списку, который вы должны выполнять итерации (и возникают проблемы с производительностью).

  • ORM API иногда непригодны для использования в реальном мире. Например, веб-приложения реального мира пытаются обеспечить изоляцию сеанса, добавив некоторые предложения WHERE при получении данных... Тогда "Session.get(id)" недостаточно, и вам нужно обратиться к более сложному DSL (HSQL, Criteria API) или вернуться к собственному SQL

  • Объекты базы данных конфликтуют с другими объектами, предназначенными для других фреймворков (например, OXM frameworks = Object/XML Mapping). Например, если ваши службы REST используют библиотеку джексона для сериализации бизнес-объекта. Но этот Джексон точно сопоставляется с Hibernate One. Затем либо вы объедините оба, и сильная связь между вашим API и вашей базой данных появится Или вы должны реализовать перевод, и весь код, который вы сохранили из ORM, потерян там...

С другой стороны, FRM представляет собой компромисс между "Реляционным сопоставлением объектов" (ORM) и собственными SQL-запросами (с JDBC)

Лучший способ объяснить различия между FRM и ORM заключается в принятии подхода DDD.

  • Реляционное сопоставление объектов позволяет использовать "Rich Object Object", которые являются классами Java, состояния которых изменяются во время транзакции базы данных.
  • Функциональное реляционное сопоставление основывается на "Бедных объектах домена", которые неизменяемы (так что вам нужно клонировать новый каждый раз, когда вы хотите изменить его содержимое).

Он освобождает ограничения, помещенные на сеанс ORM, и большую часть времени полагается на DSL над SQL (так что переносимость не имеет значения) Но, с другой стороны, вы должны изучить детали транзакции, проблемы concurrency

List<Person> persons = queryFactory.selectFrom(person)
  .where(
    person.firstName.eq("John"),
    person.lastName.eq("Doe"))
  .fetch();

Ответ 4

Я предполагаю, что функционал для реляционного сопоставления должен быть проще создавать и использовать, чем OO для РСУБД. Пока вы только запрашиваете базу данных, то есть. Я действительно не вижу (пока), как вы могли бы легко обновлять базы данных без побочных эффектов.

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

Ответ 5

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

Но для чтения функциональный язык может быть более естественным с некоторыми проблемными областями (как кажется, независимо от БД)

Функциональное отображение <-> RDBMS не должно иметь больших отличий от отображений OO <-> RDMBS. Но я думаю, что это во многом зависит от того, какие типы данных вы хотите использовать, если вы хотите разработать программу с новой схемой БД или сделать что-то против устаревшей схемы БД и т.д.

Например, ленивые извлечения и т.д. Для ассоциаций могут быть реализованы довольно хорошо с некоторыми концепциями ленивой оценки -related. (Хотя с OO их тоже можно сделать довольно красиво)

Редактировать: С некоторым поиском я нашел HaskellDB (библиотека SQL для Haskell) - что может стоить попробовать?

Ответ 6

Я не выполнял функционально-реляционное сопоставление, по сути, но я использовал методы функционального программирования для ускорения доступа к РСУБД.

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

Кажется разумным. Но проблема в том, что это может стать очень медленным. Если вашему вычислению требуется другой оператор SQL помимо самого запроса на обновление или даже нужно сделать в коде приложения, вы буквально должны (повторно) искать записи, которые вы меняете после вычисления, чтобы хранить результаты в правильных строках.

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

I (ab) использовал RDBMS таким образом и в итоге написал инструкции SQL, которые выглядели в основном так...

create table temp_foo_1 as select ...;
create table temp_foo_2 as select ...;
...
create table foo_results as
  select * from temp_foo_n inner join temp_foo_1 ... inner join temp_foo_2 ...;

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

Я предполагаю, что это также облегчило бы parallelism.

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

Ответ 7

Базы данных и функциональное программирование могут быть объединены.

например:

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

               Clojure -> DBMS, Super Foxpro
                   STM -> Transaction,MVCC
Persistent Collections -> db, table, col
              hash-map -> indexed data
                 Watch -> trigger, log
                  Spec -> constraint
              Core API -> SQL, Built-in function
              function -> Stored Procedure
             Meta Data -> System Table

Примечание: в последней спецификации spec2 спецификация больше похожа на RMDB. смотрите: spec-alpha2 wiki: Schema-and-select

Я выступаю за: построение реляционной модели данных поверх хэш-карты для достижения сочетания преимуществ NoSQL и RMDB. На самом деле это обратная реализация posgtresql.

Печатание утки: Если это похоже на утку и крякает как утка, это должна быть утка.

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

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

Все RMDB

Реализация реляционной модели данных и программирования на основе хэш-карты (NoSQL)