在 Datomic 中添加实体和 1:M 引用

问题描述 投票:0回答:1

我有一种情况,我有一个实体 A,其基数:许多引用实体 B。

A 已被事务处理到数据库。我正在寻找添加实体 B 并将其添加到 A 的 ref 属性的最有效方法。

例如,已交易的实体 A 可能如下所示:

(def john
  {:teacher/first "John"
   :teacher/last "Doe"
   :teacher/email "[email protected]"})

尚未成为的实体 B 可能如下所示:

(def brandon {:student/id (d/squuid)
              :student/first "Brandon"
              :student/last "Smith"})

我希望我可以通过 ref 字段将 B 附加到 A 上发出交易,但这似乎不起作用:

(d/transact conn [(conj john {:user/students brandon})])
;; ==> ":db.error/not-an-entity Unable to resolve entity: :user/students",

;; ==> ":db.error/not-an-entity Unable to resolve entity: :user/students",

我让它工作的唯一方法是一个笨拙的序列,我在其中处理实体 B,查询其 ID,然后将它们链接起来:

(let [brandon-tx (d/transact conn [brandon])
      new-db (:db-after @brandon-tx)
      brandon-id (-> (d/q '[:find (pull ?e [*])
                            :in $ ?bid
                            :where [?e :student/id ?bid]] new-db (:student/id brandon)) ffirst :db/id)
      tx [:db/add john-id :teacher/students brandon-id]
      result (d/transact conn [tx])
      ]
  result)

是否有更好的方法来处理实体 B 并在 A 中引用它?完整代码如下:

(require '[datomic.api :as d])

(def uri "datomic:mem://db")

(d/create-database uri)

(def conn (d/connect uri))
(def db (d/db conn))

(def schema
  ;; teachers
  [{:db/ident :teacher/first
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}
   {:db/ident :teacher/last
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}
   {:db/ident :teacher/email
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one
    :db/unique :db.unique/identity}
   {:db/ident :teacher/students
    :db/valueType :db.type/ref
    :db/cardinality :db.cardinality/many}

   ;; students
   {:db/ident :student/first
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}
   {:db/ident :student/last
    :db/valueType :db.type/string
    :db/cardinality :db.cardinality/one}
   {:db/ident :student/id
    :db/valueType :db.type/uuid
    :db/cardinality :db.cardinality/one
    :db/unique :db.unique/identity}
   ])

(d/transact conn schema)

;; teachers
(def john
  {:teacher/first "John"
   :teacher/last "Doe"
   :teacher/email "[email protected]"})

(def jane
  {:teacher/first "Jane"
   :teacher/last "Doe"
   :teacher/email "[email protected]"})

(d/transact conn [john jane])
;; #<promise$settable_future$reify__8061@7dd5e085:
;; {:db-before datomic.db.Db@723be74,
;;  :db-after datomic.db.Db@35baf542,
;;  :tx-data
;;  [#datom[13194139534316 50 #inst "2023-08-05T17:37:44.466-00:00" 13194139534316 true]],
;;  :tempids
;;  {-9223301668109598125 17592186045418,
;;   -9223301668109598124 17592186045419}}>

@(def all-teachers (d/q '[:find (pull ?e [*])
                          :where [?e :teacher/email]] (d/db conn)))

;; ==> [[{:db/id 17592186045418,
;;        :teacher/first "John",
;;        :teacher/last "Doe",
;;        :teacher/email "[email protected]"}]
;;        :db/id 17592186045419,
;;        :teacher/first "Jane",
;;        :teacher/last "Doe",
;;        :teacher/email "[email protected]"}]]

;; students

(def ashley {:student/id (d/squuid)
             :student/first "Ashley"
             :student/last "Johnson"})

(def brandon {:student/id (d/squuid)
              :student/first "Brandon"
              :student/last "Smith"})


;; add students to a teacher

@(def john-id (ffirst (d/q '[:find ?e
                             :where
                             [?e :teacher/email "[email protected]"]] (d/db conn))))

@(def add-brandon-to-john (conj john {:user/students brandon}))
;; ==> {:teacher/first "John",
;;      :teacher/last "Doe",
;;      :teacher/email "[email protected]",
;;      :user/students #:student{:id #uuid"7e098355-3ce8-4a7d-bd47-d7ea4e0819a4",
;;                               :first "Brandon",
;;                               :last "Smith"}}

;; fails

(d/transact conn [(conj john {:user/students brandon})])
;; ==> ":db.error/not-an-entity Unable to resolve entity: :user/students",

;; succeeds

(let [brandon-tx (d/transact conn [brandon])
      new-db (:db-after @brandon-tx)
      brandon-id (-> (d/q '[:find (pull ?e [*])
                            :in $ ?bid
                            :where [?e :student/id ?bid]] new-db (:student/id brandon)) ffirst :db/id)
      tx [:db/add john-id :teacher/students brandon-id]
      result (d/transact conn [tx])
      ]
  result)
clojure datomic
1个回答
0
投票

事实证明我重构后并没有更新一些代码。我可以一步添加实体 B 并引用它。

user
应该是
teacher

(d/transact conn [(conj john {:teacher/students brandon})])

© www.soinside.com 2019 - 2024. All rights reserved.