在 Rails 中是否可能有一个复合外键?

5
假设有以下数据模式:
Usage
======
client_id
resource
type
amount

Billing
======
client_id
usage_resource
usage_type
rate

在这个例子中,假设我有多个资源,每个资源都可以以多种方式使用。例如,一个资源是一个“小部件”。小部件可以被“foo”和“bar”。Gizmos也可以被“foo”和“bar”。这些用法类型按不同的费率计费,甚至可能为不同的客户设置不同的费率。每个用法(资源的用法)的发生记录在Usage表中。每个计费率(针对客户、资源和类型组合)存储在billing表中。
(顺便说一句,如果这个数据模式不是解决这个问题的正确方法,请提出建议。)
使用Ruby on Rails和ActiveRecord,是否可以从Billings到Usages创建has_many关系,以便我可以获取给定计费率的用法实例列表?是否有我不知道的“has_many, :through”的语法?
再次强调,我可能从错误的角度来解决这个问题,因此如果您能想到更好的方法,请说出来!
2个回答

6
似乎在sourceforge上有一个项目,旨在扩展Rails的ActiveRecord,以支持复合主键。我没有使用过这个扩展,但它可能会对您有所帮助。它也是rubyforge上的一个gem。
截至版本2.0,普通的Ruby on Rails不支持复合主键(参见如何使用传统架构)。每个表必须有一个名为"id"的单列自增键。
我看到的解释是:"只有在使用传统数据库时才需要复合主键。"这当然是一种非常无知的数据建模观点。
我看到的解决方案是:
  • Usage.client_id -> Client.id → Client.id 用于 Usage
  • Usage.type_id -> Usagetype.id → Usagetype.id 用于 Usage
  • Usage.resource_id -> Resource.id → Resource.id 用于 Usage
  • Billing.usage_id -> Usage.id → Usage.id 用于 Billing
  • Billing.client_id -> Client.id → Client.id 用于 Billing
  • Billing.type_id -> Usagetype.id → Usagetype.id 用于 Billing
  • Billing.resource_id -> Resource.id → Resource.id 用于 Billing

Billing 中表现出的冗余外键试图强制实施部分引用完整性。但它并没有完全实现 - 它不能防止您在 Billing 中创建引用 Usage 中具有错误客户端/资源/使用类型组合的行,这些组合与 Billing 表中的引用行不匹配。

编辑: @Yarik: 是的,你是对的。对于 Usage 引用 Billing 更有意义。

  • Usage.billing_id -> Billing.id → Billing.id 用于 Usage

嗯。我做了一个 ER 图,但我无法将其插入为图片。


等一下...难道不应该反过来吗——在Billing中有一个主键,在Usage中有一个外键吗? - Yarik
好的回答,背景很好。对我来说,RoR对数据库的看法似乎有问题。但是数据库管理系统通过让RoR承担缓慢、不可扩展的数据库负担的声誉来报复它。 - dkretz

1

你可以使用迁移中的“execute”命令创建任何约束。

你可能想要添加一些错误处理到.save中,以处理约束抛出错误的情况。

你不能使用AR的内置方法生成器来生成账单用法,但你仍然可以拥有该方法:

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接