Clojure 克洛朱尔的ORM?

Clojure 克洛朱尔的ORM?,clojure,clojureql,Clojure,Clojureql,我正在阅读有关clojure web堆栈的网站: 关于clojure的ORM,它是这样说的: “由于明显的原因,Clojure没有SQL/Relational DB ORM。” 我能看到的明显原因是,当您执行clojure.contrib.sql或clojureql查询时,到对象的映射会自动发生。然而,似乎需要做一些额外的工作来处理一对多或多对多的关系(尽管可能没有太多的工作) 我发现这篇文章是一对多的: 我不确定我是否同意;它似乎假设两个表都是从数据库中提取出来的,然后在内存中过滤连接的表。

我正在阅读有关clojure web堆栈的网站:

关于clojure的ORM,它是这样说的:

“由于明显的原因,Clojure没有SQL/Relational DB ORM。”

我能看到的明显原因是,当您执行clojure.contrib.sql或clojureql查询时,到对象的映射会自动发生。然而,似乎需要做一些额外的工作来处理一对多或多对多的关系(尽管可能没有太多的工作)

我发现这篇文章是一对多的:

我不确定我是否同意;它似乎假设两个表都是从数据库中提取出来的,然后在内存中过滤连接的表。实际上,我认为sql查询将指定where条件

所以我想知道,是否有一些相当明显的方法可以通过clojureql或clojure.contrib.sql自动实现一对多关系?我唯一能想到的就是这样(使用典型的博客帖子/评论示例):


有没有什么方法可以自动实现这一概念,或者说这是最好的方法?

据我所知,目前还没有高级库来创建复杂的关系查询。有很多方法可以解决这个问题(您提供的链接是一种方法),但是即使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)))
有了它,您可以执行
(包括:用户:帖子:评论)
,并从中获取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始终是一个低级库,所以您需要等待其他高级库的存在或创建自己的库

要创建这样一个库,您可以查看JDBC的DatabaseMetaData类,以提供有关数据库模式的信息。我仍然在为使用它(和一些定制的东西)的数据库分析器工作,但我还远没有开始处理SQL查询,我可能会在2.0版中添加SQL查询。

在Clojure中不需要ORM的“明显”原因是因为习惯性Clojure本身没有对象

在Clojure程序中表示数据的最佳方法是使用简单数据结构(映射和向量)的惰性序列。与成熟的ORM相比,将这些映射到SQL行要简单得多,阻抗不匹配的情况也要少得多


另外,关于您的问题中有关形成复杂SQL查询的部分。。。阅读您的代码时,它与SQL本身相比并没有任何明显的优势。不要害怕SQL!它的功能非常好:关系数据操作。

我很久以前问过这个问题,但我遇到了以下问题,并决定添加它作为答案,以防有人感兴趣:


冒着与一些重量级人物在水中游泳的风险(完全混合我的隐喻;)-ORM的最佳特性之一当然是,在绝大多数情况下,务实的程序员永远不必使用甚至不必考虑SQL。在最坏的情况下,可能需要一些带有几个查询结果的黑客编程,当然,在需要优化时,这将转换为原始SQL;)

说ORM不是因为“显而易见”的原因而需要的,这有点失题了。进一步使用DSL对SQL建模会加剧这一错误。在绝大多数web框架中,对象模型是一种DSL,用于描述web应用程序存储的数据,而SQL只是与数据库通信所需的声明性语言

使用ROR、django或Spring时的步骤顺序:

  • 以OOP格式描述您的模型
  • 打开REPL并制作一些示例模型
  • 构建一些视图
  • 在web浏览器中检查结果
  • 好的,你可能会使用稍微不同的顺序,但希望你能理解重点。用SQL或DSL来描述它是一个很长的路要走。取而代之的是,模型层将所有SQL抽象掉,从而允许我们创建数据对象,这些数据对象将我们希望在网站中使用的数据紧密地建模

    我完全同意OOP不是万能的,然而,在web框架中建模数据绝对是一件好事,而利用clojure定义和操作Java类的能力似乎是一个很好的匹配


    问题中的例子清楚地说明了SQL有多痛苦,而像Korma这样的DSL只是部分解决方案:“假设我们在数据库中有一些表…”-呃,我以为我的DSL会为我创建这些表?或者这仅仅是OOP语言做得更好的事情吗?;)

    你查过科尔马图书馆了吗?它允许您定义表关系和抽象over join。我认为clojure没有任何ORM的一个主要原因是,它们违背了Rich Hickey的简单思想,而这种思想正是该语言的基础。查看本讲座:

    名为的图书馆可以解决您的大部分瘙痒问题。它不是一个全面的ORM,但是如果您告诉它数据库模式的关系图,那么它提供了自动遍历关系图的CRUD实现。如果您已经在使用诸如Yesql或原始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)