有段时间没做Rails项目了, 最近准备开始一个新的Rails项目.简单的复习了一下,才发现的确有一些相对少用的特性已经有点遗忘.在此做个记录,也算加深个映像.
Rails中实现单表继承(Single-Table Inheritance)
单表继承这个概念其实是要解决面向对象与关系数据库的一个矛盾或者说不同.在关系数据库中我们并没有继承这个概念.
而单表集成解决这个问题的方式是,将父类和所有子类的属性的并集全部存入一张数据库表中,同时加入一个type字段(Rails默认其为type),来区别此条记录是属于哪一个子类的对象.
下面我举个简单的例子:
model:
script/console
>> m = Manager.create(:name => 'Calvin', :email => 'calvin@god.com', :bonus => 100000.00, :subsidy => 200.00)
>> e = Employee.new(:name => 'Terry', :email => 'Terry@god.com',:subsidy => 200.00)
>>e.manager = m
>>c = Customer.create(:name => 'Gates', :email => 'Gates@god.com', :address => 'USA')
此时我们可以看看数据库:
[img]http://dl.iteye.com/upload/attachment/142487/3ccc5fd0-33f9-3f74-abe5-e600c1cfcf05.png[/img]
然后我们可以做一些查询.
>> m = Person.find_by_name("Calvin")
=> #<Manager id: 1, type: "Manager", name: "Calvin", email: "calvin@god.com", bonus: #<BigDecimal:23c17c8,'0.1E6',4(12)>, subsidy: #<BigDecimal:23c178c,'0.2E3',4(8)>, manager_id: nil, address: nil, created_at: "2009-09-03 09:47:40", updated_at: "2009-09-03 09:47:40">
>> e = Employee.find_by_name("Terry")
=> #<Employee id: 2, type: "Employee", name: "Terry", email: "Terry@god.com", bonus: nil, subsidy: #<BigDecimal:237fc9c,'0.2E3',4(8)>, manager_id: 1, address: nil, created_at: "2009-09-03 09:55:54", updated_at: "2009-09-03 09:56:24">
>> e.manager
=> #<Manager id: 1, type: "Manager", name: "Calvin", email: "calvin@god.com", bonus: #<BigDecimal:237a418,'0.1E6',4(12)>, subsidy: #<BigDecimal:237a3dc,'0.2E3',4(8)>, manager_id: nil, address: nil, created_at: "2009-09-03 09:47:40", updated_at: "2009-09-03 09:47:40">
最后我们来看看,单表继承的利弊.
好处自不用说,我们用一张表就能存储所有子类的信息.不用为每一个子类创建常见一张表,从数据库的设计角度来讲,可以说是简洁了许多.
但是缺点也很明显每条记录都拥有所有子类的属性,冗余显得比较大.
按DHH的话来说, 这没有一个标准的选择, 只是一种取舍. 他更倾向于用单表继承而已.
关于单表继承更详细的一些阐述也可以参见Martin Fowler的<<企业应用架构模式>>
Rails中实现单表继承(Single-Table Inheritance)
单表继承这个概念其实是要解决面向对象与关系数据库的一个矛盾或者说不同.在关系数据库中我们并没有继承这个概念.
而单表集成解决这个问题的方式是,将父类和所有子类的属性的并集全部存入一张数据库表中,同时加入一个type字段(Rails默认其为type),来区别此条记录是属于哪一个子类的对象.
下面我举个简单的例子:
create_table :people do |t|
t.string :type
#公共属性
t.string :name
t.string :email
#manager的属性:分红
t.decimal :bonus, :precision => 10, :scale => 2
#developer的属性: 电脑补助
t.decimal :subsidy, :precision => 4, :scale => 2
#customer属性: 地址
t.string :address
t.timestamps
end
model:
#person.rb
class Person < ActiveRecord::Base
end
#employee.rb
class Employee < Person
belongs_to :manager, :class_name => "Employee"
end
#manager.rb
class Manager < Employee
end
#customer.rb
class Customer < Person
end
script/console
>> m = Manager.create(:name => 'Calvin', :email => 'calvin@god.com', :bonus => 100000.00, :subsidy => 200.00)
>> e = Employee.new(:name => 'Terry', :email => 'Terry@god.com',:subsidy => 200.00)
>>e.manager = m
>>c = Customer.create(:name => 'Gates', :email => 'Gates@god.com', :address => 'USA')
此时我们可以看看数据库:
[img]http://dl.iteye.com/upload/attachment/142487/3ccc5fd0-33f9-3f74-abe5-e600c1cfcf05.png[/img]
然后我们可以做一些查询.
>> m = Person.find_by_name("Calvin")
=> #<Manager id: 1, type: "Manager", name: "Calvin", email: "calvin@god.com", bonus: #<BigDecimal:23c17c8,'0.1E6',4(12)>, subsidy: #<BigDecimal:23c178c,'0.2E3',4(8)>, manager_id: nil, address: nil, created_at: "2009-09-03 09:47:40", updated_at: "2009-09-03 09:47:40">
>> e = Employee.find_by_name("Terry")
=> #<Employee id: 2, type: "Employee", name: "Terry", email: "Terry@god.com", bonus: nil, subsidy: #<BigDecimal:237fc9c,'0.2E3',4(8)>, manager_id: 1, address: nil, created_at: "2009-09-03 09:55:54", updated_at: "2009-09-03 09:56:24">
>> e.manager
=> #<Manager id: 1, type: "Manager", name: "Calvin", email: "calvin@god.com", bonus: #<BigDecimal:237a418,'0.1E6',4(12)>, subsidy: #<BigDecimal:237a3dc,'0.2E3',4(8)>, manager_id: nil, address: nil, created_at: "2009-09-03 09:47:40", updated_at: "2009-09-03 09:47:40">
最后我们来看看,单表继承的利弊.
好处自不用说,我们用一张表就能存储所有子类的信息.不用为每一个子类创建常见一张表,从数据库的设计角度来讲,可以说是简洁了许多.
但是缺点也很明显每条记录都拥有所有子类的属性,冗余显得比较大.
按DHH的话来说, 这没有一个标准的选择, 只是一种取舍. 他更倾向于用单表继承而已.
关于单表继承更详细的一些阐述也可以参见Martin Fowler的<<企业应用架构模式>>
本文介绍了如何在Rails项目中使用单表继承(STI)技术,通过一个具体示例展示了如何设计数据库表结构,并实现了不同子类的数据存储。此外,还讨论了单表继承的优缺点。

被折叠的 条评论
为什么被折叠?



