假复合主键?轨道

时间:2011-03-07 22:59:30

标签: ruby-on-rails

我有一个id为| patient_id | client_id | active的表。记录是patient_id唯一的,client_id意味着每个客户每个患者应该只有一个登记。通常我会把它作为主键,但在rails中我将id作为我的主键。

执行此操作的最佳方法是什么?验证

3 个答案:

答案 0 :(得分:8)

听起来你有一个模特关系:

class Client < ActiveRecord::Base
  has_many :patients, :through => :enrollments
  has_many :enrollments
end

class ClientPatient < ActiveRecord::Base
  belongs_to :client
  belongs_to :patient
end

class Patient < ActiveRecord::Base
  has_many :clients, :through => :enrollments
  has_many :enrollments
end

要强制执行约束,我会在ActiveRecord中执行此操作,以便在尝试保存打破约束的记录时获得正确的反馈。我只想修改你的ClientPatient模型:

class Enrollment < ActiveRecord::Base
  belongs_to :client
  belongs_to :patient
  validates_uniqueness_of :patient_id, :scope => :client_id
end

要小心,因为虽然这对于小规模应用程序来说非常好,但它仍然容易出现如下所述的竞争条件:http://apidock.com/rails/v3.0.5/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of在“并发和完整性”下

正如他们在那里描述的那样,您还应该为数据库中的表添加唯一索引。这将带来两个直接的好处:

  • 验证检查以及基于这两个ID的此模型的任何搜索都会更快(因为它们被编入索引)
  • 唯一性限制将强制执行DB端,并且在极少发生竞争条件时,您不会将错误数据保存到数据库中...尽管如果您没有捕获,用户将获得500服务器错误错误。

在迁移文件中添加以下内容:

add_index :enrollments, [:patient_id, :client_id], :unique => true

希望这有用:)

编辑(修复了一些命名问题和一些明显的错误):

然后很容易找到您正在寻找的数据:

Client.find_by_name("Bob Smith").patients
Patient.find_by_name("Henry Person").clients

答案 1 :(得分:1)

验证会起作用(Back them up with a unique index!),但是无法在vanilla Rails中获得真正的复合主键。如果你想要一个真正的复合主键,你需要一个gem / plugin - composite_primary_keys就是我找到的那个,但我确信还有其他的。

希望这有帮助!

答案 2 :(得分:0)

在两列中为表添加UNIQUE约束。这是MySQL http://dev.mysql.com/doc/refman/5.0/en/constraint-primary-key.html

的参考