假设我有 5 张桌子。ActiveRecord 可以处理这个吗?你会如何设置它?
层次结构:
Account (Abstract)
CorporateCustomer (Abstract)
PrivateCustomer
PublicCustomer
GovernmentCustomer
编辑:在休眠和城堡活动记录中,启用此场景所需的方法称为“加入子类”。
假设我有 5 张桌子。ActiveRecord 可以处理这个吗?你会如何设置它?
层次结构:
Account (Abstract)
CorporateCustomer (Abstract)
PrivateCustomer
PublicCustomer
GovernmentCustomer
编辑:在休眠和城堡活动记录中,启用此场景所需的方法称为“加入子类”。
您可以尝试以下方式。
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 belongs_to 对象。这可以由 ActiveRecord 使用多态关系映射。
在《Agile Web Development with Rails》一书中对这个问题有很好的讨论 (从第 2 版的第 341 页开始)
这是一种方法(最简单的):
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
注意:抽象模型是不能有对象(不能被实例化)的模型,因此它们也没有关联的表。如果你想有表,那么我不明白为什么它需要一个抽象类。
搜索 ActiveRecord单表继承功能。不幸的是,我无法在网上找到更详细的参考链接。我读到的最详细的解释来自“The Rails Way”一书。
假设大部分数据是共享的,您只需要一张表:accounts。假设帐户具有字符串类型列,这将起作用。
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 摘要,以获得更多有用的信息。