嗯,STI 是单表继承,CTI是类表继承..
好久没看,马丁花的博客改版了吔...
简单方案:继承图变成 ER 图...
Bowler has_one Cricketer has_one Player Footballer has_one Player
#1 楼 @luikore 我感觉类表继承比单表继承应用场景更多,但是 Rails 默认支持的却是单表继承。
#2 楼 @hooopo 话说单表继承都几乎没用过... 一旦各 model 出现了继承关系也会增加测试和 reload 的难用 ...
行为重用完全可以 mixin
而字段重用并没有节省数据库的空间,还白白增加很多 join 查询
我觉得数据库字段就该简单粗暴,Footballer 有 name 属性就该直接让带 name 字段而不是到 Player 表去找...
#4 楼 @luikore 你说这种叫实体表继承? 缺点:
#3 楼 @luikore +1
不知道是不是我用法不对,STI 带来的好处已经被别的地方需要写更多的代码抵消了
#5 楼 @hooopo 实体表继承的空间占用其实比 CTI 少... super class 对应的字段还要保存的,而且 CTI 那张图没把 record in super class 的 id 写出来
用 migration 添加字段就是套个循环而已...
遍历所有 Player 就是把 4 个表的结果加上不难吧,用单表/类表继承循环体内往往还要判断记录的类型,一不小心就 +1 查询了。
#5 楼 @hooopo 出现这么复杂的需求可能就不要用关系型数据库了吧
#7 楼 @luikore 仔细算了一下,是实体表继承占用的空间少.. 遍历四个表的结果不难,难在排序/分页之类。 N + 1 在 Rails 里不是大问题,因为做 Eager Loading 很容易。
以前喜欢用 STI,现在不喜欢。controller 和 view 复用麻烦。现在倾向于 mixin 和 table 组合的方式。
#9 楼 @hooopo 如果你 eager loading 了,不就等于在内存中做了实体表么...
#11 楼 @luikore 我想实体表最大的问题是如果实体表再 has_many 其他实体的时候,就需要引人多态了。 如果使用实体表继承,comments 或者要分两个表存成 issue_comments 和 pull_reuqest_comments,或者使用多态(多的空间在这里..)。
但是用单表和类表是很自然的事情。
class Issue < AR::Base has_many :comments has_many :watches end class PullRequest < AR::Base has_many :comments has_many :watches end