Можно ли иметь составной внешний ключ в рельсах? - PullRequest
5 голосов
/ 11 ноября 2008

Предположим, следующая схема данных:

Usage
======
client_id
resource
type
amount

Billing
======
client_id
usage_resource
usage_type
rate

В этом примере предположим, что у меня есть несколько ресурсов, каждый из которых можно использовать по-разному. Например, один ресурс - widget. Widgets может быть foo ed, и они могут быть bar ed. Gizmo s также может быть foo ed и bar ed. Эти типы использования оплачиваются по разным ставкам, возможно, даже по разным тарифам для разных клиентов. Каждый случай использования (ресурса) записывается в таблицу использования. Каждый тариф (для клиента, ресурса и комбинации типов) хранится в таблице счетов.

(Кстати, если эта схема данных не является правильным способом решения этой проблемы, пожалуйста, внесите предложения.)

Можно ли, используя Ruby on Rails и ActiveRecord, создать отношение has_many из Биллингса в Использование, чтобы я мог получить список экземпляров использования для данного тарифа выставления счетов? Есть ли синтаксис has_many, :through, который я не знаю?

Еще раз, я могу подойти к этой проблеме с неправильной точки зрения, поэтому, если вы можете придумать лучший способ, пожалуйста, говорите!

Ответы [ 2 ]

6 голосов
/ 11 ноября 2008

Очевидно, в sourceforge существует проект по расширению ActiveRecord в Rails с поддержкой составных первичных ключей . Я не использовал это расширение, но оно может вам помочь. Это также драгоценный камень в rubyforge.

Обычный Ruby on Rails, начиная с версии 2.0, не поддерживает составные первичные ключи (см. HowToUseLegacySchemas ). Каждая таблица должна иметь один столбец с автоинкрементным ключом с именем "id".

Объяснение, которое я видел, таково: «Вам нужны только составные первичные ключи, если вы хотите использовать устаревшую базу данных». Это, конечно, смехотворно невежественное представление о моделировании данных.

Решение, которое я вижу, будет:

  • Usage.client_id -> Client.id
  • Usage.type_id -> Usagetype.id
  • Usage.resource_id -> Resource.id
  • Billing.usage_id -> Usage.id
  • Billing.client_id -> Client.id
  • Billing.type_id -> Usagetype.id
  • Billing.resource_id -> Resource.id

Внешне избыточные внешние ключи в Billing пытаются обеспечить частичную ссылочную целостность. Но это не совсем так - это не мешает вам создавать строки в Billing, которые ссылаются на строку в Usage с неправильной комбинацией клиент / ресурс / тип использования, не совпадая с таковыми в ссылочной строке в Billing таблица.

edit: @Yarik: да, вы правы. Usage имеет больше смысла для ссылки Billing.

  • Usage.billing_id -> Billing.id

Хм. Я сделал диаграмму ER, но у меня возникли проблемы с ее вставкой в ​​виде изображения.

1 голос
/ 04 июля 2009

Вы можете создать любое желаемое ограничение с помощью команды execute в процессе миграции.

Возможно, вы захотите добавить некоторую обработку ошибок в .save, чтобы иметь дело со случаями, когда ограничение выдает ошибку.

Вы не можете использовать встроенные генераторы методов AR для генерации использования за счет, но у вас все еще может быть метод:

class Billing
  def usages
    Usage.find(:all, :conditions => ["x = ? and y = ?", self.x, self.y])
  end
end
...