39

clojure Web スタックに関するこのサイトを読んでいました。

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

また、clojure の ORM について次のように述べています。

「明らかな理由から、Clojure 用の SQL/リレーショナル DB ORM はありません。」

明らかな理由は、clojure.contrib.sql または clojureql クエリを実行すると、オブジェクトへのマッピングが自動的に行われることです。ただし、1 対多または多対多の関係を行うには、追加の作業が必要なようです (ただし、それほど多くの作業は必要ありません)。

1 対多の記事を見つけました: http://briancarper.net/blog/493/

私が同意するかどうかはわかりません。両方のテーブルがデータベースからプルされ、結合されたテーブルがメモリ内でフィルター処理されると想定しているようです。実際には、SQL クエリは where 基準を指定すると思います。

だから私は疑問に思っています.clojureqlまたはclojure.contrib.sqlを介して1対多の関係を自動的に行うかなり明白な方法はありますか? 私が考えることができる唯一のことは、次のようなものです(典型的なブログ投稿/コメントの例を使用):

(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)))

この概念を自動化する方法はありますか、それともうまくいきますか?

4

8 に答える 8

30

かなり前にこの質問をしましたが、次のことに出くわし、誰かが興味を持っている場合に備えて回答として追加することにしました。

http://sqlkorma.com/

于 2012-01-22T18:31:25.160 に答える
29

Clojure で ORM 自体が必要ない「明らかな」理由は、慣用的な Clojure 自体にはオブジェクトがないためです。

Clojure プログラムでデータを表現する最良の方法は、単純なデータ構造 (マップとベクトル) の遅延シーケンスとして使用することです。これらを SQL 行にマッピングすることは、本格的な ORM よりもはるかに複雑ではなく、インピーダンスの不一致もはるかに少なくなります。

また、複雑な SQL クエリの作成に関連する質問の一部について...コードを読むと、SQL 自体よりも明確な利点はありません。SQL を恐れないでください。その機能、つまりリレーショナル データ操作に最適です。

于 2011-09-17T23:08:48.567 に答える
11

私が知っている複雑なリレーショナルクエリを作成するための高レベルのライブラリはまだありません。この問題に取り組む方法はたくさんありますが(提供したリンクは一方向です)、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)

ただし、この手法には1つの大きな問題があります。主な問題は、すべてのテーブルに対して返される列が同じマップにまとめられることです。列名は自動的に修飾できないため、異なるテーブルに同じ名前の列がある場合は機能しません。これにより、スキーマにアクセスせずに結果をグループ化することもできなくなります。この種のデータベーススキーマを知らない方法はないと思うので、まだやるべきことがたくさんあります。ClojureQLは常に低レベルのライブラリのままであると思うので、他の高レベルのライブラリが存在するのを待つか、独自のライブラリを作成する必要があります。

このようなライブラリを作成するには、JDBCのDatabaseMetaDataクラスを常に調べて、データベーススキーマに関する情報を提供することができます。私はまだそれを使用するLobos(およびいくつかのカスタムのもの)のデータベースアナライザーに取り組んでいますが、バージョン2.0で追加する可能性のあるSQLクエリの作業を開始するにはまだほど遠いです。

于 2011-09-16T07:35:08.873 に答える
1

アグリゲートとして知られるライブラリは、ここで発生するほとんどの問題を処理できます。これは本格的な ORM ではありませんが、データベース スキーマの関係グラフを指定すると、関係グラフを自動的にたどる CRUD 実装が提供されます。単純な結果マップを使用する実装に簡単にプラグインできるため、Yesql や生の SQL クエリなどを既に使用している場合に便利です。

于 2016-03-08T11:38:51.253 に答える