我有一个架构,其中两个实体之间存在父子关系。它是一对多的,因此自然会实现为:
table Parents
id
table Children
id
parent_id
但是,我还需要将其中一个 child 作为特例(我们称其为“提升” child )。我可以想到几种方法来做到这一点,包括:
只需在 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
这让我可以放置一个唯一索引,从而加强数据库的一致性。这样做的一个问题是,可能存在一种无意义的关系,其中 parent A 的 child 列为 parent B 的晋升者。
我能想到的最后一个选择是创建一个中间表,例如:
table Parents
id
table Children
id
table ParentChildRelationship
parent_id
child_id
is_promoted
同样,我可以在 parent_id
+is_promoted
上声明一个唯一约束,以加强一致性。我对此有点矛盾,因为将关系提升为完整实体似乎有点矫枉过正,尽管我在其上放置属性的那一刻(本质上是 is_promoted
是),我想这是有道理的.
我想知道您认为处理此问题的规范方法是什么。特别是,我正在使用 Rails,因此这可能会影响最实用的解决方案。
最佳答案
我没有任何 Rails 经验,但在处理 1 到多个关系的默认值时遇到过类似的情况,并且通常对数据库模式使用类似这样的东西:
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
Jef 提出的对 (parent_id, is_promoted) 的唯一约束将在数据库忽略空值时起作用,正如 Kelvin 所建议的那样,这可能是一个不错的选择。但是,有些人可能会争辩说,使用 null 代替 false/0 是对 null 的错误使用,它有效地将字段转换为三态,即 1、0、unknown。此外 (parent_id, is_promoted) 不是 superkey因此违反了Domain Key Normal Form .
table Parents
id
promoted_child_id
table Children
id
parent_id
正如您所指出的,这可能会导致循环,并且通过使 promoted_child_id 成为引用 Children(id) 的 FK,您仍然面临数据库异常的风险,其中 ParentA 将 ParentB 的 child 列为已提升。
table Parents
id
table Children
id
parent_id
promoted_parent_id
在这里,您会遇到所描述的异常风险; promoted_parent_id 上的唯一键也必须依赖数据库忽略空值;多个级联路径;作为 promoted_parent_id 和 parent_id 的冗余应该是相同的;更新 parent_id 与 promoted_parent_id 不匹配的异常。
table Parents
id
table Children
id
table ParentChildRelationship
parent_id
child_id
is_promoted
这看起来更像是 parent 对 child 的多对多表示。它提出了与上述其他问题类似的问题。
至于rails开发什么最实用我不好说。我已经使用了我提出的表示法和 Jef 的 C# 和 PHP 表示法,并没有真正注意到差异。
关于ruby-on-rails - 我如何最好地表示一个 child 是特例的一对多关系?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14135700/