Single table inheritance:单表继承

[align=center][size=x-large]Single table inheritance:单表继承[/size][/align]


转于:[url]http://my4java.itpub.net/post/9983/78535[/url]
一、介绍:

关系数据库不支持继承,所以在将对象映射到数据库时,我们必须考虑如何在关系表中表现我们完美的继承结构。当映射到一个关系数据库时,我们试图最小化在多个表内处理一个继承体系时快速增长的结合。单表继承则将一个继承体系的所有类映射到单个表的字段中。

在一个关系数据库内至少可以有三种形式来表现继承体系。Martin Fowler 在[url]http://www.martinfowler.com/eaaCatalog/[/url]中做了简短的描述。

1、Class Table Inheritance:继承体系中的每个类都由单个表来表现。

2、Single Table Inheritance:继承体系中的所有类都由一个单独表中的列来表现。

3、Concrete Table Inheritance:继承体系中的每个具体类由单个表来表现。

可参考下面的链接:

1、 [url]http://www.martinfowler.com/eaaCatalog/classTableInheritance.html[/url]

2、 [url]http://www.martinfowler.com/eaaCatalog/singleTableInheritance.html[/url]

3、 [url]http://www.martinfowler.com/eaaCatalog/concreteTableInheritance.html[/url]

二、“活动记录”的支持:

“活动记录”使用第二种途径来支持继承,这意味着你必须添加一个string列,通过在列中存储类的名字,而此列缺省地称为,“type”(可以通过覆写Base.inheritance_column来修改缺省名称)。这意味着一个继承看起来是这样的:

class Company < ActiveRecord::Base; end

class Firm < Company; end

class Client < Company; end

class PriorityClient < Client; end


当你完成Firm.create(:name => "37signals"),这个记录将被保存在companies表中且type="firm"。然后你可以使用Company.find(:first, "name = ‘37signals’")来获取此行,并且它会返回一个Firm对象。

如果你没有在你的表内定义type列,则不会触发单表继承。这种情况下,它只是像普通子类一样工作没什么魔术可用。

注意,所有的属性必须位于同一表内。

[color=indigo][b]注意:Rails在使用STI类之前必须能看到包含它们的文件,否则你会得到“uninitialized constant”错误。如果类的名字与包含它的文件的名称不是同样的话,你可能要有麻烦。如果你在'employees.rb'文件内有个“模型”为Manager。在这种情况下,Rails将不能从类名字中分析出文件名。

解决这个问题最简单的方式是添加“model :employees”到你的application.rb“控制器”中,那里'employees'是不带扩展名的,包含STI类的文件名(所以解决上面问题,“模型”应该包含文件名'employees.rb‘才可以。)这会强迫Rails加载此文件并看到你在其内定义的所有“模型”,然后在你使用时,Rails已经知道了你的STI类。[/b][/color]

使用Employee[:type]来访问子表信息,不要使用Employee.type。type是一个Ruby废弃的方法,所以直接访问它来设置或修改行的type会导致陌生的Ruby消息。

在使用“单个表继承时“有个明显的约束。两个子类不能有同样名字但不同type的属性,那样两个属性将被映射为同一个列。

三、例子:

# simplified

def new

case @params[:person_type]

when "Manager"

@person = Manager.new

when "Slave"

@person = Slave.new

end

end

在你的“视图”中,完成:

<%= hidden_field_tag "person_type", @person[:type] %>

然后是create方法:

#again, simplified

def create

case @params[:person_type]

when "Manager"

@person = Manager.new(@params[:person])

when "Slave"

@person = Slave.new(@params[:person])

end

if @person.save

redirect_to :action => :list

else

render_action :new

end

end

甚至你可以在你的Person类中创建一个factory类方法。

class Person < ActiveRecord::Base

def self.factory(type, params = nil)

case type

when "Manager"

return Manager.new(params)

when "Slave"

return Slave.new(params)

else

return nil

end

end

end

然后,你可以在new和create方法内完成

def new

@person = Person.factory(@params[:person_type])

end

def create

@person = Person.factory(@params[:person_type], @params[:person])

if @person.save

...

end

end

你也可以使用下面方式来创建一个子类(thanks to Sean Hussey/Ezra)

person_type = "Manager"

@person = eval(person_type + ".new")

或者使用 constantize:

person_type = "Manager"

@person = person_type.constantize.new

如果你的“type”列的文本没有精确地匹配你的类名字,你可能得这样做:

class ETH < ListData; end

Ethnicity = ETH
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值