新手问题 有在 AR 里用过 CTI 的没

hooopo · 2013年07月15日 · 最后由 hooopo 回复于 2013年07月17日 · 3138 次阅读

嗯,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 你说这种叫实体表继承? 缺点:

  • 在基表添加字段麻烦
  • 空间占用多
  • 实现“遍历所有 Player”这种需求就困难了(在单表继承和类表继承里很容易)

#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
需要 登录 后方可回复, 如果你还没有账号请 注册新账号