我有一种情况,我有一个实体 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)
事实证明我重构后并没有更新一些代码。我可以一步添加实体 B 并引用它。
user
应该是teacher
。
(d/transact conn [(conj john {:teacher/students brandon})])