【问题标题】:ORM for clojure?用于clojure的ORM?
【发布时间】:2011-09-08 17:09:39
【问题描述】:

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

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

关于 clojure 的 ORM 有这样的说法:

“由于显而易见的原因,没有用于 Clojure 的 SQL/关系数据库 ORM。”

我可以看到的明显原因是,当您执行 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)))

有没有办法让这个概念自动化,或者这是否尽可能好?

【问题讨论】:

  • 许个愿:你想如何更简洁地编码/声明/写这个?
  • 我对“显而易见的原因”的看法是,对象关系映射在非面向对象的语言中没有意义。
  • @Kevin:如果你想要修补和精细控制,你需要 SQL,而不是 ORM,因为 ORM 使最简单的事情变得微不足道,但复杂的事情变得不可能或过于复杂。
  • @ivant:ORM 不是一个好名字,但这个概念对于非面向对象的语言仍然有效。在 Clojure 中,您可以将关系映射到映射或类型/记录。后者在将继承放在一边时与对象完全同构。
  • Marko Kocić,您的陈述可能与琐碎或糟糕的 ORM 有关。 ORM 是个好东西。它使代码更干净,更可重用。 Rails 的带有新 ARel 功能的 Active Records 允许您使用原始 sql 完成 97% 的操作。我不得不用 PostgreSQL 做一些相当复杂的事情,而 ARel 完全可以做到这一点,而无需退回到原始 SQL。

标签: clojure clojureql


【解决方案1】:

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

http://sqlkorma.com/

【讨论】:

【解决方案2】:

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

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

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

【讨论】:

  • 很好的答案。 clojure 的哲学拒绝带有动词的对象的概念,因此完全拒绝 ORM
【解决方案3】:

据我所知,仍然没有创建复杂关系查询的高级库。有很多方法可以解决这个问题(您提供的链接是一种方法),但即使 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 将始终是一个低级库,因此您需要等待其他更高级别的库存在或创建自己的库。

要创建这样的库,您可以随时查看 JDBC 的 DatabaseMetaData 类以提供有关数据库模式的信息。我仍在为Lobos 开发一个使用它的数据库分析器(以及一些自定义的东西),但我离开始处理 SQL 查询还有很长的路要走,我可能会在 2.0 版中添加它。

【讨论】:

  • 将此标记为正确,因为我感谢您在答案中付出的努力,并且它最接近我正在寻找的东西的类型。
【解决方案4】:

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

说出于“显而易见”的原因不需要 ORM,这有点不合时宜。进一步开始使用 DSL 对 SQL 进行建模会加剧这个错误。在绝大多数 Web 框架中,对象模型一种 DSL,用于描述 Web 应用程序存储的数据,而 SQL 仅仅是将其与数据库通信所需的声明性语言。

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

  1. 以 OOP 格式描述您的模型
  2. 打开 REPL 并制作一些示例模型
  3. 构建一些视图
  4. 在网络浏览器中查看结果

好的,所以您可能会使用稍微不同的顺序,但希望您能明白这一点。在 SQL 或描述它的 DSL 中思考是一个很长的路要走。取而代之的是,模型层将所有 SQL 抽象出来,从而使我们能够创建数据对象,以对我们希望在网站中使用的数据进行密切建模。

我完全同意 OOP 不是灵丹妙药,但是,在 Web 框架中建模数据绝对是它的优势所在,利用 clojure 定义和操作 Java 类的能力在这里似乎是一个很好的匹配。

问题中的示例清楚地展示了 SQL 的痛苦程度,而像 Korma 这样的 DSL 只是部分解决方案:“假设我们在数据库中有一些表......” - 呃,我以为我的 DSL 正在运行为我创造那些?或者这只是 OOP 语言做得更好的事情? ;)

【讨论】:

    【解决方案5】:

    您查看过 Korma 库 http://sqlkorma.com/ 吗?它允许您定义表关系和抽象连接。我认为 clojure 没有任何 ORM 的一个主要原因是因为它们违背了 Rich Hickey 的简单思想,该语言是建立在该语言之上的。看看这个演讲:http://www.infoq.com/presentations/Simple-Made-Easy

    【讨论】:

      【解决方案6】:

      名为aggregate 的库可以解决您在这里遇到的大部分问题。它不是一个完整的 ORM,但如果你告诉它数据库模式的关系图,那么它会提供自动遍历关系图的 CRUD 实现。如果您已经在使用 Yesql 或原始 SQL 查询之类的东西,它会很有用,因为它很容易插入到使用简单结果映射的实现中。

      【讨论】:

        【解决方案7】:

        不管你要不要用,已经有aggregate 现在有toucan(他们显然阅读了与您相同的链接)。

        【讨论】:

          【解决方案8】:

          ORM 是过早的优化。 Walkable 是 Clojure 的新 sql 库,采用整体方法。在这里查看https://github.com/walkable-server/walkable

          对于那些对花哨的自述文件持怀疑态度的人的真实示例:https://github.com/walkable-server/realworld

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-03-21
            • 1970-01-01
            • 1970-01-01
            • 2019-02-10
            • 1970-01-01
            • 2011-04-21
            • 2017-03-26
            • 2020-10-18
            相关资源
            最近更新 更多