tro*_*skn 6 database ruby-on-rails cardinality
我有一个在两个实体之间具有父子关系的模式.它是一对多的,所以自然会被实现为:
table Parents
id
table Children
id
parent_id
Run Code Online (Sandbox Code Playgroud)
但是,我还需要将其中一个孩子视为一个特殊情况(让我们称之为"晋升"的孩子).我可以想到几种方法,包括:
只需输入一个属性Children:
table Parents
id
table Children
id
parent_id
is_promoted
Run Code Online (Sandbox Code Playgroud)
这显然是有缺陷的,因为数据库不能保证一致性(至少不能通过常规外键约束)
在Parents表上创建一个外键:
table Parents
id
promoted_child_id
table Children
id
parent_id
Run Code Online (Sandbox Code Playgroud)
这是我的第一个倾向,但它确实有一个循环依赖的明显缺点,所以可能不是最优的.
我能想到的另一个选择是在Children桌面上放置第二个外键:
table Parents
id
table Children
id
parent_id
promoted_parent_id
Run Code Online (Sandbox Code Playgroud)
这允许我放置唯一索引,从而强制数据库一致性.这样做的一个问题是,有可能产生无意义的关系,其中父母A的孩子列为父母B的提升者.
我能想到的最后一个选项是创建一个中间表,例如:
table Parents
id
table Children
id
table ParentChildRelationship
parent_id
child_id
is_promoted
Run Code Online (Sandbox Code Playgroud)
同样,我可以在parent_id+ 上声明一个唯一约束is_promoted,强制执行一致性.我对这个问题有点矛盾,因为将关系推广到一个完整的实体似乎有些过分,尽管我把它放在它上面的那一刻(实质上is_promoted就是这个),我想这是有道理的.
我想知道你会考虑用什么方法来处理这个问题.特别是,我正在使用Rails,因此可能会影响最实用的解决方案.
小智 2
我没有任何 Rails 经验,但在处理一对多关系的默认值时遇到过类似的情况,并且通常对数据库模式使用类似的内容:
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
Run Code Online (Sandbox Code Playgroud)
回答这个问题后,我开始思考为什么我更喜欢这种表示而不是其他表示,所以我做了更多的研究并进行了更多的思考:
table Parents
id
table Children
id
parent_id
is_promoted
Run Code Online (Sandbox Code Playgroud)
如果按照 Kelvin 的建议,如果数据库忽略空值,那么 Jef 提出的对 (parent_id, is_promoted) 的唯一约束将起作用,并且可能是一个不错的选择。然而,有些人可能会认为使用 null 代替 false/0 是 null 的错误用法,它有效地将字段变成三态,即 1、0、未知。此外 (parent_id, is_promoted) 不是超级键,因此违反了域键范式。
table Parents
id
promoted_child_id
table Children
id
parent_id
Run Code Online (Sandbox Code Playgroud)
正如您所指出的,这可能会导致循环,并且通过将promoted_child_id设置为引用Children(id)的FK,您仍然面临数据库异常的风险,其中ParentA将ParentB的孩子列为升级。
table Parents
id
table Children
id
parent_id
promoted_parent_id
Run Code Online (Sandbox Code Playgroud)
在这里,您会遇到所描述的异常风险;Promotion_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
Run Code Online (Sandbox Code Playgroud)
这看起来更像是父对子的多对多表示。它提出了与上述其他问题类似的问题。
至于什么对于 Rails 开发来说是最实用的,我不能说。我已经使用了我提出的表示法和 Jef 的 C# 和 PHP 表示法,但并没有真正注意到差异。