clojure 中关系数据库中的一个_model_ 数据如何?
Posted
技术标签:
【中文标题】clojure 中关系数据库中的一个_model_ 数据如何?【英文标题】:how does one _model_ data from relational databases in clojure? 【发布时间】:2011-03-05 06:43:59 【问题描述】:我已经在 Twitter 和 #clojure IRC 频道上问过这个问题,但没有得到任何回应。
有几篇关于 Clojure-for-Ruby-programmers、Clojure-for-lisp-programmers 的文章。但缺少的是 Clojure for ActiveRecord 程序员。
已经有关于与 MongoDB、Redis 等交互的文章 - 但这些都是在一天结束时的键值存储。然而,由于来自 Rails 背景,我们习惯于从继承的角度来考虑数据库——has_many、多态、belongs_to 等。
关于 Clojure/Compojure + mysql (ffclassic) 的几篇文章 - 深入研究 sql。当然,也有可能是 ORM 导致了阻抗不匹配,但事实是,像 ActiveRecord 那样思考之后,再想其他方式是非常困难的。
我相信关系数据库非常适合面向对象的范式,因为它们本质上是集合。像 activerecord 这样的东西非常适合对这些数据进行建模。 例如一个博客——简单地说
class Post < ActiveRecord::Base
has_many :comments
end
class Comment < ActiveRecord::Base
belongs_to :post
end
如何在 Clojure 中对此进行建模 - 它是如此严格地反 OO ?如果它涉及所有函数式编程语言,也许这个问题会更好,但从 Clojure 的角度来看我更感兴趣(和 Clojure 示例)
【问题讨论】:
一个相关问题:***.com/questions/2740916 -- 我已经提供了对该问题的答案,可能对这个问题有用。 感谢 Michal - 我特别喜欢您根据哈希描述表建模的方式。我想知道你是否可以详细说明你的答案,比如外键、单表继承、连接...... 【参考方案1】:现在有几个类似 ORM 的库正在开发中。
clj-record Carte Oyako (免责声明,这是我写的。) ClojureQL 在我看来更像是一个生成 SQL 的库,但值得一提。在邮件列表中,一些(聪明的)人最近描述了一些other models for how this might work。这些库中的每一个都对问题采取了相当不同的方法,因此请务必查看所有库。
例如,这是一个使用 Oyako 的extended example。这个库还没有准备好生产并且仍在大量开发中,所以这个例子可能会在一周内失效,但它已经到了那里。无论如何,这都是一个概念验证。给它一些时间,有人会想出一个好的库。
请注意,clojure.contrib.sql
已经允许您从数据库(通过 JDBC)获取记录,并最终得到表示记录的不可变哈希映射。因为数据最终会出现在法线贴图中,所以在贴图上工作的无数 Clojure 核心函数都已经在这些数据上工作了。
ActiveRecord 还能为您提供什么?我能想到几件事。
简洁的 SQL 查询 DSL
我在心理上对此建模的方式:首先定义表之间的关系。这不需要突变或对象。这是一个静态的描述。 AR 将这些信息分散在一堆类中,但我将其视为一个单独的(静态)实体。
使用定义的关系,您可以以非常简洁的方式编写查询。以亲子为例:
(def my-data (make-datamap db [:foo [has-one :bar]]
[:bar [belongs-to :foo]]))
(with-datamap my-data (fetch-all :foo includes :bar))
然后您将拥有一些 foo
对象,每个对象都有一个列出您的条的 :bar
键。
在 Oyako 中,“数据地图”只是一张地图。查询本身就是一张地图。返回的数据是地图矢量(地图矢量)。所以你最终得到了一种标准的、简单的方法来构造、操作和迭代所有这些东西,这很好。添加一些糖(宏和普通函数),让您更轻松地简洁地创建和操作这些地图,它最终变得非常强大。这只是一种方式,还有很多方法。
如果您查看像 Sequel 这样的库作为另一个示例,您会得到以下内容:
Artist.order(:name).last
但是为什么这些函数必须是存在于对象内部的方法呢? Oyako 中的等价物可能是:
(last (-> (query :artist)
(order :name)))
保存/更新/删除记录
再一次,为什么你需要 OO 风格的对象或突变或实现继承呢?首先获取记录(作为不可变映射),然后通过一系列函数将其线程化,assoc
根据需要将新值写入其中,然后将其填充回数据库或通过调用其上的函数将其删除。
一个聪明的库可以利用元数据来跟踪哪些字段已被更改,以减少进行更新所需的查询量。或者标记记录,以便数据库函数知道将其粘贴回哪个表。我认为 Carte 甚至会进行级联更新(当父记录发生更改时更新子记录)。
验证、钩子
我认为其中大部分属于数据库而不是 ORM 库。例如,级联删除(删除父记录时删除子记录):AR 有办法做到这一点,但您可以将一个子句扔到数据库中的表上,然后让您的数据库处理它,再也不用担心了。与多种约束和验证相同。
但是如果你想要钩子,可以使用简单的旧函数或多方法以非常轻量级的方式实现它们。在过去的某个时候,我有一个数据库库,它在 CRUD 循环的不同时间调用钩子,例如 after-save
或 before-delete
。它们是对表名进行调度的简单多方法。这使您可以根据需要将它们扩展到您自己的表中。
(defmulti before-delete (fn [x] (table-for x)))
(defmethod before-delete :default [& _]) ;; do nothing
(defn delete [x] (when (before-delete x) (db-delete! x) (after-delete x)))
然后作为最终用户,我可以写:
(defmethod before-delete ::my_table [x]
(if (= (:id x) 1)
(throw (Exception. "OH NO! ABORT!"))
x))
简单且可扩展,只需几秒钟即可编写。看不到OO。可能不如 AR 复杂,但有时简单就足够了。
查看this library 了解另一个定义挂钩的示例。
迁移
Carte 有这些。我没有过多考虑它们,但是对数据库进行版本控制并将数据插入其中似乎并没有超出 Clojure 的可能性范围。
波兰语
AR 的许多优点来自于命名表和命名列的所有约定,以及用于大写单词和格式化日期等的所有便利功能。这与 OO 与非 OO 无关; AR 只是有很多润色,因为它已经投入了很多时间。也许 Clojure 还没有用于处理数据库数据的 AR 类库,但请给它一些时间。
所以...
与其拥有一个知道如何销毁自身、变异自身、保存自身、将自身与其他数据相关联、获取自身等的对象,相反,您拥有的数据只是数据,然后您定义了处理该数据的函数数据:保存它、销毁它、在数据库中更新它、获取它、将它与其他数据相关联。这就是 Clojure 对数据的一般操作方式,来自数据库的数据也不例外。
Foo.find(1).update_attributes(:bar => "quux").save!
=> (with-db (-> (fetch-one :foo :where :id 1)
(assoc :bar "quux")
(save!)))
Foo.create!(:id => 1)
=> (with-db (save (in-table :foo :id 1)))
类似的东西。它与对象的工作方式完全不同,但它提供了相同的功能。但是在 Clojure 中,您还可以获得以 FP 方式编写代码的所有好处。
【讨论】:
超级!!这几乎就是我一直在寻找的——我想知道你是否可以为 oyako 添加示例。问题是我们(在这种情况下——我)太习惯于思考对象——大多数框架都鼓励我们。与 MVC 之类的概念相关的概念很难理解不变性的概念——命令式 MVC 和函数式 MVC 之间存在什么概念差异。这就是为什么我没有找到任何关于编写与 relational DB 交互的 Web 应用程序的 clojure/compojure 示例(除了您自己编写的示例)(不像 Scala,它最终是 OO)【参考方案2】:这个问题已经有一段时间没有人回答了,但是 Korma http://sqlkorma.com 是另一个有助于减少 SQL 和 Clojure 之间不协调的项目。它是最近才进行的,应该可以与最近的 Clojure 版本一起使用。
【讨论】:
【参考方案3】:一个基于 clojure.contrib.sql 的新 micro SQL DSL 已经启动。它位于 Github 上,重量为 76 位置。
作者的博客上有很多 DSL 背后的例子和理论,链接在他的 Github 个人资料上(新用户 SO 超链接限制 bah)。我觉得它的设计允许将 SQL 抽象为更惯用的 Clojure。
【讨论】:
以上是关于clojure 中关系数据库中的一个_model_ 数据如何?的主要内容,如果未能解决你的问题,请参考以下文章