Как мне смоделировать это отношение множественного наследования с Ruby ActiveRecord? - PullRequest
2 голосов
/ 19 июня 2009

Если у меня есть 5 таблиц. Может ли ActiveRecord справиться с этим? Как бы вы это настроили?

Иерархия:

Account (Abstract)
  CorporateCustomer (Abstract)
    PrivateCustomer
    PublicCustomer
  GovernmentCustomer

Редактировать: В nhibernate и castle activerecord метод, необходимый для включения этого сценария, называется "присоединенные подклассы".

Ответы [ 4 ]

4 голосов
/ 20 июня 2009

Вы можете попробовать что-нибудь в следующем духе.

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.

Но библиотека ActiveRecord в Rails не реализует "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, например, объект имеет_a index_entry и index_entry принадлежит_ к объекту. Это может быть сопоставлено ActiveRecord с использованием полиморфных отношений.

В книге очень хорошо обсуждается эта проблема "Гибкая веб-разработка с Rails" (начиная со страницы 341 во втором издании)

0 голосов
/ 19 июня 2009

Это один (самый простой) способ сделать это:

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

ПРИМЕЧАНИЕ. Абстрактные модели - это модели, которые не могут иметь объекты (не могут быть созданы) и, следовательно, не имеют связанной таблицы. Если вы хотите иметь таблицы, то я не понимаю, зачем нужен абстрактный класс.

0 голосов
/ 19 июня 2009

Предполагая, что большая часть данных является общей, вам нужна только одна таблица: учетные записи. Это будет просто работать, при условии, что в аккаунтах есть столбец строкового типа.

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 для Rails STI и, в частности, резюме Rails STI, для получения более полезной информации.

0 голосов
/ 19 июня 2009

Поиск ActiveRecord Функция наследования одной таблицы . К сожалению, я не могу найти более подробную ссылку онлайн для ссылки. Самое подробное объяснение, которое я прочитал, было из книги «Путь рельсов».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...