Обновление транзакции в Datomic для атрибута с большим числом элементов

Я искал два дня и не видел ни одного закрытого для этого кода. Это единственный код на java, который я видел, и это не совсем то, что я хотел.

conn.transact(list(list("db.fn/cas", datomic_id, "attribute you want to update", old value, new value))).get();

Я пробовал этот код с одним значением в старом значении и одним значением в новом значении, но он просто складывает информацию, а не накладывает ее. Пример: старое значение — курица, новое значение — рыба. После транзакции это [курица, рыба], а не то, что я ожидал, будет просто [рыба], и курица будет перемещена в архив (история).

Итак, вопрос в том, как вы ссылаетесь на старое значение массива и как вы даете новому значению массив, чтобы он обновлялся так, как я ожидал, как указано выше.

Я помню, где-то читал, что под капотом это просто ряд значений, связанных с одним атрибутом. Если это так, значит ли это, что я должен найти идентификатор datomic строки и изменить его? Также нужно удалить его, если его нет в новом списке?


person pompanoSlayer    schedule 01.04.2016    source источник


Ответы (2)


К вашему сведению, это общие функции транзакций, которые я в настоящее время использую для такого рода задач (объявлены из 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])}),
  }]

Я вовсе не утверждаю, что они оптимальны по производительности или дизайну, но до сих пор они работали на меня. ХТН.

person Valentin Waeselynck    schedule 02.04.2016

Если вам нужно согласованное решение в стиле «последняя запись выигрывает» для замены всех значений для конкретной сущности для атрибута «много карт», лучше всего использовать функция транзакции. Вы можете использовать следующий подход:

  1. Получите все данные, соответствующие объекту + атрибуту, для которого вы хотите отозвать все значения.
  2. Создайте опровержения для всех из них.
  3. Создать транзакции добавления для всех новых значений (например, из переданной коллекции)
  4. Удалите все конфликты (например, если у вас есть один и тот же EAV с добавлением и результатом)
  5. Верните полученные данные транзакции.
person Ben Kamphaus    schedule 02.04.2016
comment
Я предполагаю, что это сгенерирует две транзакции. Один, чтобы убрать все значения, а другой, чтобы добавить их обратно? Я пошел другим путем, создав еще одно пространство имен с массивом. Таким образом, я просто создаю новое пространство имен и меняю ссылку на это новое. Я не знаю, быстрее ли это или ваш способ быстрее. - person pompanoSlayer; 04.04.2016
comment
Вы создаете одну транзакцию (возвращаете полученные данные транзакции), просматривая две коллекции данных (что есть и что вы хотите там видеть). Тем не менее, мои шаги многословны, и вы можете просто подтвердить разницу после проверки, например. pull, что, вероятно, является лучшим решением. - person Ben Kamphaus; 04.04.2016
comment
Похоже, если бы я следовал модели сущностей и предикатов Datomic, это привело бы меня к вашему решению VS моему. Это становится нечетким, когда я добавляю другие объекты, чтобы помочь с этой проблемой. - person pompanoSlayer; 05.04.2016