ORM的clojure?
我正在读这个网站关于clojurenetworking堆栈:
http://brehaut.net/blog/2011/ring_introduction
对于clojure来说,这有一个关于ORM的说法:
“由于显而易见的原因,Clojure没有SQL /关系数据库ORM。”
我可以看到的一个明显的原因是,当您执行clojure.contrib.sql或clojureql查询时,映射到对象会自动发生。 然而,看起来需要一些额外的工作来做一对多或多对多的关系(尽pipe可能不是太多的工作)。
我发现这写成一对多: 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)))
有没有什么办法可以使这个概念自动化呢?还是这样好呢?
仍然没有高级的库来创build我所知道的复杂的关系查询。 有很多方法可以解决这个问题(您提供的链接是一种方式),但即使ClojureQL提供了一个非常好的DSL,但它仍然会遗漏一些重要的function。 下面是一个生成重叠连接的macros的一个快速和肮脏的例子:
(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 [ab] (map #(vector %1 %2) ab)) (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将永远是一个低级库,所以你需要等待其他更高级的库存在或创build自己的库。
要创build这样的库,您可以始终查看JDBC的DatabaseMetaData类,以提供有关数据库模式的信息。 我仍然在为使用它的Lobos (以及一些自定义的东西)开发一个数据库分析器,但是我还没有开始处理SQL查询,我可能会在2.0版本中添加它。
不久前我问了这个问题,但是我碰到以下问题,并决定添加它作为答案,以防有人感兴趣:
你在Clojure中不需要ORM的“显而易见的”理由是因为惯用的Clojure本身没有对象。
在Clojure程序中表示数据的最好方法是简单的数据结构(地图和向量)的延迟序列。 将这些映射到SQL行非常简单,并且与完整的ORM相比阻抗不匹配要less得多。
此外,关于你的问题与形成一个复杂的SQL查询有关的部分…阅读你的代码,它确实没有比SQL本身明显的优势。 不要害怕SQL! 它的function非常棒:关系数据操作。
有可能在一些SO重击者的水中游泳(把我的隐喻彻底地混合起来) – 当然,ORM最好的特点之一就是绝大多数情况下,实用程序员不得不使用甚至想想SQL。 在最坏的情况下,可能需要使用几个查询的结果来进行一些冒险的编程,因为当需要优化时,这将被转换为原始SQL,当然,)。
说ORM不是“显而易见的”理由所要求的,有点不重要。 进一步开始使用DSL来build模SQL是复合这个错误。 在绝大多数Web框架中,对象模型是用于描述Web应用程序存储的数据的DSL,而SQL仅仅是将其传递到数据库所需的声明性语言。
使用ROR,Django或Spring时的步骤顺序:
- 用OOP格式描述你的模型
- 打开REPL并制作一些示例模型
- build立一些意见
- 在networking浏览器中检查结果
好的,所以你可能会用一个稍微不同的顺序,但是希望你明白这一点。 用SQL或者描述它的DSL思维还有很长的路要走。 相反,模型层将所有的SQL抽象出来,允许我们创build数据对象,对我们希望在网站中使用的数据进行精确的模型化。
我完全同意OOP不是银弹,然而,在Web框架中build模数据是绝对有好处的,利用clojure定义和操作Java类的能力在这里似乎是一个很好的匹配。
问题中的例子清楚地表明了SQL是多么痛苦,像Korma这样的DSL只是一个解决scheme:“假设我们在数据库中有一些表格……” – 呃,我以为我的DSL会创build这些为了我? 或者这只是一个OOP语言做得更好? ;)
你检查了Korma库http://sqlkorma.com/吗?; 它允许你定义表关系和抽象的连接。 我认为没有任何ORM是因为他们违背了Rich Hickey关于这个语言所依赖的简单的想法的一个主要原因。 看看这个话题: http : //www.infoq.com/presentations/Simple-Made-Easy
被称为聚合的图书馆可以照顾你在这里的大部分瘙痒。 这不是一个完整的ORM,但是如果你告诉它你的数据库模式的关系图,那么它提供了CRUD实现,它会自动遍历关系图。 如果您正在使用诸如Yesql或原始SQL查询之类的东西,这很有用,因为它可以轻松插入到使用简单结果地图的实现中。
无论你是否想要使用它们,现在已经有了聚集 ,现在有了巨嘴鸟 (而且它们显然也和你们一样阅读了相同的链接)。