2

5つのテーブルがあると仮定します。ActiveRecord はこれを処理できますか? どのように設定しますか?

階層:

Account (Abstract)
  CorporateCustomer (Abstract)
    PrivateCustomer
    PublicCustomer
  GovernmentCustomer

編集: nhibernate とキャッスル アクティブレコードでは、このシナリオを有効にするために必要なメソッドは「joined-subclasses」と呼ばれます。

4

4 に答える 4

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 を呼び出すと、type フィールドは自動的に「PrivateCustomer」に設定され、Account.find を呼び出すと、返されるオブジェクトは正しいクラスになります。

これは、あなたが望むことを行うための最も簡単な方法であるため、私がお勧めするアプローチです。

具象クラスごとに 1 つのテーブル- 私が知る限り、ActiveRecord ではこれに対するマッピングは提供されていません。この方法の主な問題は、すべてのアカウントのリストを取得するには、3 つのテーブルを結合する必要があることです。必要なのは、次のモデルにつながる何らかのマスター インデックスです。

クラスごとに 1 つのテーブル- 抽象クラスを表すテーブルは、一種の統一インデックス、または具象クラスのテーブルに格納されているオブジェクトのカタログと考えることができます。このように考えることで、is_a 関係を has_a 関係に変更することになります。これは、多態的な関係を使用して ActiveRecord によってマッピングできます。

この問題については、書籍「Agile Web Development with Rails」 (第 2 版の 341 ページから) で非常によく説明されています。

于 2009-06-20T12:25:34.290 に答える
0

これは、それを行う1つの方法(最も簡単な方法)です。

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

注:抽象モデルは、オブジェクトを持つことができない(インスタンス化できない)モデルであるため、関連付けられたテーブルもありません。テーブルが必要な場合、抽象クラスが必要な理由がわかりません。

于 2009-06-19T16:04:04.503 に答える
0

ActiveRecord の単一テーブル継承機能を検索します。残念ながら、リンクするためのより詳細なリファレンスをオンラインで見つけることができません。私が読んだ最も詳細な説明は、「The Rails Way」の本からのものでした。

于 2009-06-19T14:00:00.293 に答える
0

ほとんどのデータが共有されていると仮定すると、必要なテーブルは 1 つだけです: 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

Rails STIのGoogle、特にRails STIの要約で、さらに有用な情報を入手してください。

于 2009-06-19T17:26:05.750 に答える