mysql - Clojure中如何从关系数据库中获取一个_model_数据?

标签 mysql postgresql functional-programming clojure compojure

我在Twitter以及#clojure IRC channel 上都曾问过这个问题,但没有得到回应。

有几篇关于Clojure-for-Ruby程序员,Clojure-for-lisp-programmers的文章。但是缺少的部分是对于ActiveRecord程序员的Clojure。

已经有关于与MongoDB,Redis等进行交互的文章-但这些都是最终的关键值存储。但是,由于来自Rails的背景,我们习惯于从继承 Angular 考虑数据库-has_many,polymorphic,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中对此建模?如果它涉及所有函数式编程语言,也许这个问题会更好,但是从Clojure的观点(和Clojure示例)来看,我更感兴趣

最佳答案

如今,有一些类似ORM的库在工作。

  • clj-record
  • Carte
  • Oyako(免责声明,我写了这个。)
  • 从我所见,
  • ClojureQL更像是一个SQL生成的库,但值得一提。

  • 在邮件列表中,一些(聪明)人最近描述了一些other models for how this might work。这些库中的每一个都采用完全不同的方法来解决该问题,因此请务必对它们全部进行研究。

    例如,这是使用Oyako的extended example。该库尚未准备好投入生产,并且仍在大量开发中,因此该示例可能在一周之内无效,但是已经实现了。无论如何,这都是概念证明。给它一些时间,有人会想出一个好的图书馆。

    请注意,clojure.contrib.sql已经允许您(通过JDBC)从数据库中获取记录,并以表示记录的不可变哈希图结束。由于数据以法线贴图结尾,因此在 map 上起作用的所有无数Clojure核心功能都已在该数据上起作用。

    ActiveRecord还给您什么?我可以想到两件事。

    简洁的SQL查询DSL

    我的思维方式建模:首先,定义表之间的关系。这不需要突变或对象。这是一个静态描述。 AR将这些信息分散在许多类中,但我将其视为一个单独的(静态)实体。

    使用定义的关系,然后可以非常简洁的方式编写查询。以Oyako为例:
    (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,“数据 map ”仅是一张 map 。查询本身是一个 map 。返回的数据是 map 的 vector ( map 的 vector )。因此,您最终得到了一种标准,简单的方法来构造,操纵和迭代所有这些东西,这很好。添加一些糖(宏功能和常规功能),使您可以更轻松地简洁地创建和操作这些 map ,并且最终功能非常强大。这只是一种方式,有很多方法。

    如果再看一个类似于Sequel的库,您将看到以下内容:
    Artist.order(:name).last
    

    但是,为什么这些功能必须是存在于对象内部的方法? Oyako中的一个等效项可能是:
    (last (-> (query :artist) 
              (order :name)))
    

    保存/更新/删除记录

    同样,为什么要为此使用OO风格的对象或变异或实现继承?首先获取记录(作为不可变映射),然后通过一堆函数对其进行线程化,assoc根据需要在其上添加新值,然后将其填充回数据库或通过在其上调用函数将其删除。

    一个聪明的库可以利用元数据来跟踪更改了哪些字段,以减少进行更新所需的查询量。或者标记该记录,以便DB函数知道将其粘贴到哪个表中。我认为,Carte甚至可以级联更新(在更改父记录时更新子记录)。

    验证,挂钩

    我认为其中大部分属于数据库而不是ORM库。例如,级联删除(在删除父记录时删除子记录):AR可以做到这一点,但是您只需在数据库中的表上放置一个子句,然后让您的数据库处理它,就不用再担心了。与许多约束和验证相同。

    但是,如果您想使用钩子(Hook),可以使用普通的旧函数或多方法以非常轻巧的方式实现它们。在过去的某个时候,我有一个数据库库,它在CRUD周期的不同时间调用了钩子(Hook),例如after-savebefore-delete。它们是对表名进行分派(dispatch)的简单多方法。这使您可以根据需要将它们扩展到自己的表中。
    (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中查看定义钩子(Hook)的另一个示例。

    移居

    点菜有这些。我对它们并没有考虑太多,但是对数据库进行版本控制并将数据放入数据库中似乎并不超出Clojure的可能性。

    抛光

    AR的许多优点来自于命名表和命名列的所有约定,以及所有用于将单词大写和格式化日期等的便利功能。这与OO与非OO无关。 AR有了很多改进,因为花了很多时间。也许Clojure还没有AR类库来处理数据库数据,但请花一些时间。

    所以...

    而不是拥有一个知道如何销毁自身,变异自己,保存自己,与其他数据相关联,取回自身等的对象,而是拥有了只是数据的数据,然后定义了对该数据起作用的函数:它,销毁它,在数据库中更新它,获取它,并将其与其他数据相关联。通常,这就是Clojure对数据进行操作的方式,而数据库中的数据也不异常(exception)。
    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方式编写代码的所有好处。

    关于mysql - Clojure中如何从关系数据库中获取一个_model_数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3067261/

    相关文章:

    mysql - SQL Count() 列值

    postgresql - Play 的进化并没有在 Heroku 上运行

    sql - 结合使用 string_agg 并在 postgres 中使用

    postgresql - 如何使 postgreSQL 备份密码 protected

    c++ - 使用 lambda 将一种类型的 vector 映射到另一种类型

    haskell - 将表达式转换为字符串表示形式?

    MySQL:跨多对多和一对多(以及其他东西)进行计数

    mysql - select 语句中列的顺序会影响查询速度吗?

    mysql - 当我设置 mydumper 时,cmake 无法找到 mysql 库

    python - Python 中的函数式数据类型