ORM для clojure? - PullRequest
       49

ORM для clojure?

37 голосов
/ 08 сентября 2011

Я читал этот сайт о веб-стеке clojure:

http://brehaut.net/blog/2011/ring_introduction

и он говорит об ORM для clojure:

"НетSQL / реляционные БД ORM для Clojure по очевидным причинам. "

Очевидная причина, которую я вижу, состоит в том, что сопоставление с объектом происходит автоматически при выполнении запроса clojure.contrib.sql или clojureql.Однако кажется, что для выполнения отношений один-ко-многим или многим-ко-многим требуется дополнительная работа (хотя, возможно, не слишком много работы).

Я нашел эту запись для одного ко многим: http://briancarper.net/blog/493/

С которой я не уверен, что согласен;похоже, предполагается, что обе таблицы извлекаются из базы данных, а затем объединенная таблица фильтруется в памяти.На практике я думаю, что SQL-запрос определил бы критерии where.

Так что мне интересно, есть ли какой-то довольно очевидный способ автоматического выполнения отношений один-ко-многим через clojureql или clojure.contrib.sql?Единственное, о чем я могу думать, это что-то вроде этого (используя типичный пример поста / комментария в блоге):

(defn post [id] 
    @(-> (table :posts)
        (select (where :id id))))
(defn comments [post_id]
    @(-> (table :comments) 
         (select (where :post_id post_id))))
(defn post-and-comments [id]
    (assoc (post id) :comments (comments id)))

Есть ли способ автоматизировать эту концепцию или это так хорошо, как она есть?

Ответы [ 8 ]

28 голосов
/ 22 января 2012

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

http://sqlkorma.com/

27 голосов
/ 18 сентября 2011

«Очевидная» причина, по которой вам не нужен ORM как таковой в Clojure, заключается в том, что идиоматический Clojure не имеет объектов как таковых.

Лучший способ представления данных в программе Clojure - это ленивыйПоследовательности простых структур данных (карты и векторы).Отображение этих строк в SQL гораздо менее сложно и имеет гораздо меньшее несоответствие импеданса, чем полноценное ORM.

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

10 голосов
/ 16 сентября 2011

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

(defn parent-id [parent]
  (let [id (str (apply str (butlast (name parent))) "_id")]
    (keyword (str (name parent) "." id))))

(defn child-id [parent child]
  (let [parent (apply str (butlast (name parent)))]
    (keyword (str (name child) "."  parent "_id"))))

(defn join-on [query parent child]
  `(join ~(or query `(table ~parent)) (table ~child)
         (where
          (~'= ~(parent-id parent)
               ~(child-id parent child)))))

(defn zip [a b] (map #(vector %1 %2) a b))

(defmacro include [parent & tables]
  (let [pairs (zip (conj tables parent) tables)]
    (reduce (fn [query [parent child]] (join-on query parent child)) nil pairs)))

С этим вы можете сделать (include :users :posts :comments) и получить из него этот SQL:

SELECT users.*,posts.*,comments.*
  FROM users
  JOIN posts ON (users.user_id = posts.user_id)
  JOIN comments ON (posts.post_id = comments.post_id)

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

Чтобы создать такую ​​библиотеку, у вас всегда может бытьпосмотрите на класс DatabaseMetaData JDBC, чтобы предоставить информацию о схеме базы данных.Я все еще работаю над анализатором базы данных для Lobos , который использует его (и некоторые пользовательские вещи), но я все еще далек от того, чтобы начать работать с запросами SQL, которые я мог бы добавить в версии 2.0.

6 голосов
/ 13 ноября 2013

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

Сказать, что ORM не требуется по «очевидной» причине, несколько упускает из виду. Дальнейшее начало использования DSL для моделирования SQL усугубляет эту ошибку. В подавляющем большинстве веб-платформ объектная модель представляет собой DSL, используемый для описания данных, хранящихся в веб-приложении, а SQL - просто декларативный язык, необходимый для передачи этого в базу данных.

Порядок действий при использовании ROR, Django или Spring:

  1. Опишите ваши модели в формате ООП
  2. Откройте REPL и создайте несколько примеров моделей
  3. Построить некоторые представления
  4. Результаты проверки в веб-браузере

Хорошо, так что вы можете использовать немного другой порядок, но, надеюсь, вы поняли. Мышление в SQL или DSL, которое описывает это, далеко внизу списка. Вместо этого уровень модели абстрагирует весь SQL, что позволяет нам создавать объекты данных, которые точно моделируют данные, которые мы хотим использовать на веб-сайте.

Я бы полностью согласился с тем, что ООП не является «серебряной пулей», однако моделирование данных в веб-фреймворке - это то, для чего это определенно хорошо, и использование способности clojure для определения и манипулирования Java-классами кажется здесь хорошим совпадением.

Примеры в этом вопросе ясно демонстрируют, насколько болезненным может быть SQL, и такие DSL, как Korma, являются лишь частичным решением: «Предположим, у нас есть несколько таблиц в базе данных ...» - я думал, что мой DSL собирается создать их для меня? Или это просто что-то лучше, чем язык ООП? ;)

4 голосов
/ 25 января 2014

Вы проверили библиотеку Korma http://sqlkorma.com/? Это позволяет вам определять отношения таблиц и абстрагироваться от объединений. Я думаю, что главная причина, по которой ORM не существует для закрытия, состоит в том, что они идут вразрез с идеями Рича Хикки о простоте, на которых был основан язык. Проверьте этот разговор: http://www.infoq.com/presentations/Simple-Made-Easy

1 голос
/ 08 марта 2016

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

0 голосов
/ 04 мая 2018

ORM - преждевременная оптимизация. Walkable - это новая библиотека sql для Clojure, которая использует целостный подход. Проверьте это здесь https://github.com/walkable-server/walkable.

Реальный пример для тех, кто скептически относится к причудливым readmes: https://github.com/walkable-server/realworld

0 голосов
/ 28 сентября 2017

Хотите ли вы их использовать или нет, уже было совокупность и сейчас есть toucan (и они, видимо, читают ту же ссылку, что и вы).

...