我搜索了两天,没有看到任何与此相关的代码。这是我见过的唯一的 java 代码,但它并不完全是我想要的。
conn.transact(list(list("db.fn/cas", datomic_id, "attribute you want to update", old value, new value))).get();
我已经尝试使用旧值中的单个值和新值中的单个值来尝试此代码,但它只是堆叠信息而不是覆盖它。 示例:旧值是鸡,新值是鱼。交易后,它是[鸡,鱼],而不是我期望的只是[鱼],并且鸡将被移入文件(历史)。
所以问题是,如何引用旧数组值以及如何为新值提供一个数组,以便它将按照我预期的方式更新,如上所述。
我记得在某处读过,在幕后它只是链接到一个属性的一系列值。如果是这种情况,是否意味着我必须找到字符串的原子 id 并更改它?如果它不在新列表中,还必须将其删除吗?
最佳答案
仅供引用,这些是我目前用于此类任务的通用事务函数(从 Clojure 声明,但如果需要的话应该很容易适应 Java):
[{:db/ident :bsu.fns/replace-to-many-scalars,
:db/doc "Given an entity's lookup ref, a to-many (scalar) attribute, and a list of new values,
yields a transaction that replaces the old values by new ones"
:db/id (d/tempid :db.part/user),
:db/fn (d/function
'{:lang :clojure,
:imports [],
:requires [[datomic.api :as d]],
:params [db entid attr new-vals],
:code (let [old-vals (if-let [e (d/entity db entid)] (get e attr) ())
to-remove (remove (set (seq new-vals)) old-vals)]
(concat
(for [ov to-remove] [:db/retract entid attr ov])
(for [nv new-vals] [:db/add entid attr nv]))
)}),
}
{:db/ident :bsu.fns/to-many-retract-all-but,
:db/doc "Given an entity lookup ref, a to-many (entity) attribute, and a list of lookup refs
expands to a transaction which will retract all the [origin `to-many-attr` target] relationships but those for which target is among the `to-spare-lookup-refs`"
:db/id (d/tempid :db.part/user),
:db/fn (d/function
'{:lang :clojure,
:imports [],
:requires [[datomic.api :as d]],
:params [db origin to-many-attr to-spare-lookup-refs],
:code (let [old-targets-ids (d/q '[:find [?t ...] :in $ ?to-many-attr ?origin :where [?origin ?to-many-attr ?t]]
db to-many-attr origin)
to-spare-ids (for [lr to-spare-lookup-refs] (:db/id (d/entity db lr)))
to-delete (->> old-targets-ids (remove (set to-spare-ids)))]
(for [eid to-delete] [:db/retract origin to-many-attr eid])
#_[old-targets-ids to-update-ids to-delete])}),
}]
我根本不声称它们具有最佳性能或设计,但到目前为止它们对我来说很有效。 HTH。
关于java - 在 Datomic 中更新具有多个基数的属性的事务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36356933/