如何使用Ruby ActiveRecord建模这种多继承关系?

时间:2009-06-19 13:22:49

标签: ruby-on-rails ruby inheritance activerecord multiple-inheritance

假设我有5张桌子。 ActiveRecord可以处理这个吗?你会如何设置它?

层次结构:

Account (Abstract)
  CorporateCustomer (Abstract)
    PrivateCustomer
    PublicCustomer
  GovernmentCustomer

编辑:在nhibernate和castle activerecord中,启用此方案所需的方法称为“join-subclasses”。

4 个答案:

答案 0 :(得分:4)

您可以尝试以下几行。

class Account < ActiveRecord::Base
  belongs_to :corp_or_gov_customer, :polymorphic => true

  def account_id
    self.id
  end
end

class GovernmentCustomer < ActiveRecord::Base
  has_one :account, :as => :corp_or_gov_customer, :dependent => :destroy

  def method_missing( symbol, *args )
    self.account.send( symbol, *args )
  end
end

class CorporateCustomer < ActiveRecord::Base
  has_one :account, :as => :corp_or_gov_customer, :dependent => :destroy
  belongs_to :priv_or_pub_customer, :polymorphic => true

  def method_missing( symbol, *args )
    self.account.send( symbol, *args )
  end
end

class PrivateCustomer < ActiveRecord::Base
  has_one :corporate_customer, :as => :priv_or_pub_customer, :dependent => :destroy

  def method_missing( symbol, *args )
    self.corporate_customer.send( symbol, *args )
  end
end

class PublicCustomer < ActiveRecord::Base
  has_one :corporate_customer, :as => :priv_or_pub_customer, :dependent => :destroy

  def method_missing( symbol, *args )
    self.corporate_customer.send( symbol, *args )
  end
end

我没有测试过这段代码(甚至检查了它的语法)。相反,它只是为了指向多态关系的方向。

重写method_missing以调用嵌套对象可以保存编写代码,如

my_public_customer.corporate_customer.account.some_attribute

而你可以写

my_public_customer.some_attribute

回应评论:

问题是像“是一个”,“有很多”和“属于”这样的概念都是由关系模型中的外键关系实现的。继承的概念与RDB系统完全不同。这些关系的语义必须通过您选择的ORM技术映射到关系模型上。

但是Rails的ActiveRecord库并没有将“is_a”实现为模型之间的关系。

有几种方法可以在RDB中为类层次结构建模。

所有帐户的单个表但具有冗余属性 - ActiveRecord只需在表格中添加“类型”列即可支持此功能。然后像这样创建类层次结构:

class Account < ActiveRecord::Base
class GovernmentCustomer < Account
class CorporateCustomer < Account
class PublicCustomer < CorporateCustomer
class PrivateCustomer < CorporateCustomer

然后,如果你调用PrivateCustomer.new,类型字段将自动设置为“PrivateCustomer”,当你调用Account.find时,返回的对象将是正确的类。

这是我推荐的方法,因为它是迄今为止最简单的方法。

每个具体类的一个表 - 据我所知,在ActiveRecord中没有为此提供映射。此方法的主要问题是获取所有帐户的列表,您必须加入三个表。需要的是某种主索引,它导致下一个模型。

每个类的一个表 - 您可以将表示抽象类的表视为一种统一索引,或存储在具体类的表中的对象目录。通过这种方式考虑,你将is_a关系改为has_a关系,例如对象has_a index_entry和index_entry属于对象。这可以通过ActiveRecord使用多态关系进行映射。

本书[{3}}(从第2版第341页开始)对这个问题进行了很好的讨论。

答案 1 :(得分:0)

搜索ActiveRecord Single Table Inheritance功能。 很遗憾,我无法在网上找到更详细的参考链接。我读到的最详细的解释来自“The Rails Way”一书。

答案 2 :(得分:0)

这是这样做的一种方式(最简单):

class Account < ActiveRecord::Base
   self.abstract_class = true
   has_many :corporate_customers
   has_many :government_customers
end


class CorporateCustomer < ActiveRecord::Base
   self.abstract_class = true
   belongs_to :account
   has_many :private_customers
   has_many :public_customers
end


class PrivateCustomer < ActiveRecord::Base
   belongs_to :corporate_customer
end

class PublicCustomer < ActiveRecord::Base
   belongs_to :corporate_customer
end

class GovernmentCustomer < ActiveRecord::Base
   belongs_to :account
end

注意:抽象模型是不能拥有对象(无法实例化)的模型,因此它们也没有关联的表。如果你想拥有表,那么我就无法理解它为什么需要一个抽象类。

答案 3 :(得分:0)

假设大多数数据是共享的,您只需要一个表:帐户。这将起作用,假设帐户有一个字符串类型列。

class Account < ActiveRecord::Base
  self.abstract_class = true
end

class CorporateCustomer < Account
  self.abstract_class = true
  has_many financial_statements
end

class PrivateCustomer < CorporateCustomer
end

class PublicCustomer < CorporateCustomer
end

class GovernmentCustomer < Account
end

Google for Rails STI,特别是Rails STI摘要,以获取更多有用信息。