ActiveRecord-鏈接多張表之單表繼承

ActiveRecord-鏈接多張表之單表繼承

1. 基本概念

Rails提供了兩種機制,能夠將複雜的面向對象模型映射爲關係模型,即所謂的單表繼承(single-table inheritance)和多態關聯(polymorphic associations,也有人稱爲多表繼承)。數據庫

2. 單表繼承

在使用面向對象開發時,常常會用到類和繼承,如應用程序中涉及不一樣角色的人員(People):顧客(Customer)、員工(Employee)和經理(Manager)等等。其中有一些屬性是共有的,另外一些屬性是特有的。所以,建立模型:Customer類和Employee類,且都是People的子類,Manager類是Employee的子類。子類會繼承父類的全部屬性和行爲。ruby

這些都是代碼中的模型體現,在關係型數據庫是如何體現的?見以下代碼:架構

# model的定義
class People < ActiveRecord::Base
end

class Customer < People
end

class Employee < People
    belongs_to :boss, class_name: 'Employee', foreign_key: 'reports_to'
end

class Manager < Employee
end
# 遷移文件的定義,即關係型數據庫的體現
create_table :people, :force => true do |t|
    t.column :type, :string

    # common attributes
    t.column :name, :string
    t.column :email, :string

    # attributes for type=Customer
    t.column :balance, :decimal, :precision => 10, :scale => 2

    # attributes for type=Employee
    t.column :reports_to, :integer
    t.column :dept, :integer

    # attributes for type=Manager
    # none
end
# 添加人員

boss = Manager.create({name: 'Jobs', email: 'jobs@apple.com', dept: 1})

empl = Employee.new({name: 'David', email: 'david@apple.com', dept: 2})
empl.boss = boss
empl.save

user = Customer.create({name: 'Jim', email: 'jim@rails.com', balance: 100})

由上面的代碼能夠看出類定義中使用了繼承,而對於不一樣角色的人員,均保存於people表,對於boss和empl對象,都是沒有user的balance屬性的,即這兩個對象的balance字段都是null,而對於user對象的dept和reports_to字段一樣是null,這樣就實現了一個單表繼承,相比於咱們使用各類其它方法會簡單不少。可是問題是:app

2.1 ActiveRecord如何如此簡單的提供了單表繼承?

經過遷移文件中能夠看到,在people表中添加了type字段。經過上圖也能夠看到,每條記錄的type字段都有值,並且爲用戶的角色。ActiveRecord是約定好了使用type字段來描述對象所屬的類型。學習

針對此問題,能夠詳見Martin Fowler在《企業應用架構模式》的介紹。測試

2.2 若是一個新加入的開發者使用People添加了人員呢?

是的,也許一個新加入項目組的同窗使用People添加了人員,即便是測試,也會感受到代碼不是那麼嚴謹,例如:code

god = Person.create({name: 'God', email: 'god@god.god'})

發生了什麼?God真的是神啊,type爲空,因此,咱們必定不想在表中見到神,按以下三種方法都可以解決:對象

  • 在People中實現一個名爲abstract_class?的類方法,並使其返回true,這樣,就能夠達到目的了。不過它帶來的問題是:1.ActiveRecord永遠不會嘗試尋找對應於抽象類的數據庫表,這是對咱們有利的,2.抽象類的子類會被看成各自獨立的ActiveRecord模型類,即各自映射到一張獨立的數據庫表。這就達不到咱們對公共屬性抽取的目的了。這種方法不完美
  • 使用Ruby模塊來包含這些須要共享的功能,而後將模塊混入所謂的子類。這是書中提供的方法,也感受不完美,沒有了繼承的感受
  • 可否在父類中添加什麼使其只可讀不可寫呢?
2.3 單表繼承的優勢和缺點

單表繼承中全部的屬性都存在於一張表中,這樣真的好嗎?若是子類存在的差別較大,且屬性數據較大,若是仍然存在於同一張表,就會產生不少問題。這時能夠學習多態繼承了。blog

5. 參考

  • 《Web開發敏捷之道》第2版#P341-鏈接多張表
相關文章
相關標籤/搜索