6

我有一个具有两个实体之间的父子关系的模式。它是一对多的,所以自然会实现为:

table Parents
  id

table Children
  id
  parent_id

但是,我还需要将其中一个孩子视为特例(我们称其为“提升”孩子)。我可以想到几种方法来做到这一点,包括:

只需将属性放在Children

table Parents
  id

table Children
  id
  parent_id
  is_promoted

这显然是有缺陷的,因为数据库不能保证一致性(至少不能通过常规外键约束)

在表上创建外键Parents

table Parents
  id
  promoted_child_id

table Children
  id
  parent_id

这是我的第一个倾向,但它确实具有循环依赖的明显缺点,因此可能不是最优的。

Children我能想到的另一种选择是在桌子上放第二个外键:

table Parents
  id

table Children
  id
  parent_id
  promoted_parent_id

这允许我放置一个唯一的索引,从而强制数据库的一致性。这样做的一个问题是,可能存在一种无意义的关系,其中父母 A 的孩子列为父母 B 的提升。

我能想到的最后一个选项是创建一个中间表,例如:

table Parents
  id

table Children
  id

table ParentChildRelationship
  parent_id
  child_id
  is_promoted

parent_id同样,我可以在+上声明一个唯一约束is_promoted,强制一致性。我对此有点矛盾,因为将关系提升为一个完整的实体似乎有点矫枉过正,尽管我在它上面加上属性的那一刻(本质上is_promoted是),我想这是有道理的。

我想知道您认为处理此问题的规范方法是什么。特别是,我使用的是 Rails,所以这可能会影响最实用的解决方案。

4

2 回答 2

2

我没有任何 Rails 经验,但在处理 1 到多个关系的默认值时遇到过类似的情况,并且通常对 db 模式使用类似这样的东西:

table Parents
  id

table Children
  id
  parent_id
  FK (parent_id) references Parents(id)

table PromotedChildren
  child_id
  parent_id
  FK (child_id, parent_id) references Children(id, parent_id)
  UNIQUE Key parent_id

编辑

回答完这个问题后,我开始思考为什么我更喜欢这种表示而不是其他表示,所以我做了更多的研究并给予了更多的思考:

table Parents
  id

table Children
  id
  parent_id
  is_promoted

如果按照 Kelvin 的建议,如果 db 忽略空值,那么 Jef 建议的对 (parent_id, is_promoted) 的唯一约束将起作用,并且可能是一个不错的选择。但是,有些人可能会争辩说,使用 null 作为 false/0 的替代是对 null 的错误使用,它有效地将字段转换为三态,即 1、0、未知。此外 (parent_id, is_promoted ) 不是超级密钥,因此违反了Domain Key Normal Form

table Parents
  id
  promoted_child_id

table Children
  id
  parent_id

正如您指出的那样,这可能会导致循环,并且通过将promoted_child_id 设为引用Children(id) 的FK,您仍然面临ParentA 将ParentB 的子级列为提升的数据库异常的风险。

table Parents
  id

table Children
  id
  parent_id
  promoted_parent_id

在这里,您会遇到所描述的异常风险;在promoted_pa​​rent_id 上的唯一键也必须依赖于忽略空值的数据库;多个级联路径;作为promotion_parent_id 和parent_id 的冗余应该相同;更新 parent_id 与promoted_pa​​rent_id 不匹配的异常。

table Parents
  id

table Children
  id

table ParentChildRelationship
  parent_id
  child_id
  is_promoted

这看起来更像是父母对孩子的多对多表示。它提出了与上述其他问题类似的问题。

至于什么对 Rails 开发最实用,我不能说。我已经使用了我提出的表示法和 Jef 的 C# 和 PHP 表示法,并没有真正注意到有什么不同。

于 2013-01-03T11:18:31.127 回答
1

parent_id您可以在和列上应用唯一约束is_promoted以确保完整性并避免您提到的其他两个解决方案的缺点。它在查询时也应该表现得很好。

于 2013-01-03T18:33:46.663 回答