Datomic:具有“重置”操作的多对多关系模式 [英] Datomic: schema for a to-many relationship with a 'reset' operation

查看:88
本文介绍了Datomic:具有“重置”操作的多对多关系模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找有关在Datomic中对某些关系建模的方法的反馈。



问题



假设我要为一个人在其中拥有喜欢的电影列表的域设计Datomic模式。例如, John 最喜欢的电影是 Gladiator Star Wars Fight Club



在Datomic中对此建模最明显的方案是基数很多属性,例如:

 #{[ John:person / favorite-movies Gladiator] 
[ John:个人/最爱电影星球大战]
[ John:个人/最爱电影战斗俱乐部]}

通过这种方法,可以轻松地从列表中添加或删除电影(只需使用:db / add :db / retract ),但是我发现重置整个电影列表是不切实际的-实际上,您需要计算新列表与新列表之间的差异,并且必须在交易功能中运行。当列表的元素不是标量时,情况甚至更糟。



替代方法



,我正在考虑使用 set实体引入间接操作:

 #{[ John :人/最爱电影42] 
[42:set.string /包含角斗士]
[42:set.string /包含星球大战]
[42:set。字符串/包含 Fight Club]}

通过这种方法,:person / favorite-movies 是基数一,ref类型的属性,而:set.string / contains 是基数多,字符串类型的属性。重置列表然后只需创建一个新的 set实体

  [{:db / id John 
:人员/收藏夹电影{:db / id(d / tempid:db.part / user)
:set.string /包含[ Gladiator
指环王
发条橙
真实的浪漫]}}]

这种对多对关系建模的方法是否存在已知限制?






编辑:一个不那么平凡的用例



在关系是引用类型的情况下研究此问题更有意义,不是标量类型的,因为Datomic中的ref类型的属性会出现一些问题。



研究用例中关系的重置操作更有意义,而喜欢的电影并非如此,这更有意义。 / p>

示例:带有复选框的表单,用户可以在其中提供答案到通过选择一组 Option 来解决问题。用户可以将她的答案更新为问题。目标是为答案-期权关系建模。



此信息模型的规范Datomic模式为:




  • :answer / id :答案的唯一ID(标量类型,唯一身份)

  • :option / id :选项的唯一ID(标量类型,唯一身份)

  • :answer / selectedOptions (引用类型,基数很多)


解决方案

使用这种方法进行了几个月的实验,这是我的结论。



两种策略( A-使用直接属性,而B-使用中间可抛弃实体)在读写方面有实际的优缺点,可以在问题弗朗西斯·阿维拉的答案。但是恕我直言,最重要的原则是: 模式应主要由域模型确定,而不是由读写模式 确定。



是否存在适用于策略B的域模型?我相信是这样。



例如,在问题中出现的问题/选项/答案示例域中,将一组答案解释为一个更有意义整体而不是个别事实。将:submittedTime 即时类型的属性添加到中介实体,现在您已经对答案的修订进行了建模(您不想要






注意:



使用策略A,实施重置操作需要交易功能;由于与实体生命周期有关的棘手问题(该实体是否已经存在),在最一般的情况下编写这样的事务功能并不容易。最好的拍摄方法是在Datofu库中找到的 。 / p>

I'm looking for feedback on an approach for modeling certain to-many relationships in Datomic.

The problem

Suppose I want to design the Datomic schema for a domain where a Person has a list of favorite Movies. For instance, John's favorite movies are Gladiator, Star Wars, and Fight Club.

The most obvious schema for modeling this in Datomic is with a cardinality-many attribute, e.g:

#{["John" :person/favorite-movies "Gladiator"]
  ["John" :person/favorite-movies "Star Wars"]
  ["John" :person/favorite-movies "Fight Club"]}

This approach makes it easy to add or remove movies from the list (simply use :db/add and :db/retract), but I find it impractical for resetting the whole list of movies - you essentially need to compute a diff between the old list and the new, and that has to run in a transaction function. This gets even worse when the elements of the list are not scalars.

Alternative approach

As an alternative approach, I'm considering introducing an indirection using a set entity:

#{["John" :person/favorite-movies 42]
  [42 :set.string/contains "Gladiator"]
  [42 :set.string/contains "Star Wars"]
  [42 :set.string/contains "Fight Club"]}

With this approach, :person/favorite-movies is a cardinality-one, ref-typed attribute, and :set.string/contains is cardinality-many, string-typed attribute. Resetting the list is then simply a matter of creating a new set entity:

[{:db/id "John"
  :person/favorite-movies {:db/id (d/tempid :db.part/user)
                           :set.string/contains ["Gladiator" 
                                                 "The Lord of the Rings"
                                                 "A Clockwork Orange"
                                                 "True Romance"]}}]

Are there known limitations to this approach of modeling to-many relationships?


Edit: A less trivial use case

It's more relevant to study this problem in a case where the relationship is ref-typed, not scalar-typed, because some issues on appear with ref-typed attributes in Datomic.

It's also more relevant to study a use case where a 'reset' operation for the relationship makes more sense, which is not really the case for 'favorite movies'.

Example: A form with checkboxes, in which a user may provide an Answer to a Question by selecting a set of Options. The user may update her Answer to the Question. The goal is to model the Answer - Option relationship.

A canonical Datomic schema for this information model would be:

  • :answer/id: unique id of the answer (scalar-typed, unique-identity)
  • :option/id: unique id of the option (scalar-typed, unique-identity)
  • :answer/selectedOptions (ref-typed, cardinality-many)

解决方案

Having experimented for a few months with this approach, here are my conclusions.

Both strategies (A - using a direct attribute vs B - using an intermediary, disposable entity) have practical advantages and drawbacks when it comes to reading and writing, as can be read in the question and Francis Avila's answer. But IMHO, the most important principle is this: the schema should be primarily determined by the domain model, not by the read and write patterns.

Are there domain models for which strategy B is appropriate? I believe so.

For instance, in the Question/Option/Answer example domain presented in the question, it may make more sense for the set of answers to be interpreted a cohesive whole rather than separate individual facts. Add a :submittedTime instant-typed attribute to the intermediary entity, and you've now modeled a revision of the answer (you don't want to rely on Datomic history to model that).


Note:

With Strategy A, implementing a 'reset' operation requires a transaction function; because of tricky concerns related to entity lifecycle ('does this entity already exist or not'), such a transaction function is not trivial to write in the most general case. My best shot at this can be found in the Datofu library.

这篇关于Datomic:具有“重置”操作的多对多关系模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆