Ruby on Rails多表JOIN关联优化:三表ActiveRecord查询方案问询
解决Rails 6.0.1中跨表关联查询的ActiveRecord写法(无需改表)
针对你遇到的遗留系统关联问题,可以通过给模型添加带动态条件的关联来替代原生SQL JOIN,完全用ActiveRecord方法链实现查询,且无需修改任何数据表结构。
方案一:在PersonShift模型中添加关联
给PersonShift模型定义一个has_one关联,匹配对应的Employee记录(同一个Person,且所属公司与Shift的公司一致):
class PersonShift < ApplicationRecord belongs_to :person belongs_to :shift enum status: { ongoing: "ongoing" } # 关联到对应的Employee:person_id匹配,且公司与shift所属公司一致 has_one :employee, ->(person_shift) { where(company_id: person_shift.shift.company_id) }, foreign_key: :person_id, primary_key: :person_id end
使用该关联查询
现在可以完全用ActiveRecord的链式方法替代原生JOIN:
date = Date.today # 获取所有拥有活跃班次的员工ID active_employee_ids = PersonShift.ongoing .joins(:shift, :employee) .where(shifts: { date: date }) .distinct .pluck(:employee_id) # 统计数量 active_employee_count = active_employee_ids.size
方案二:在Employee模型中添加反向关联
如果更习惯从Employee视角查询,可以给Employee模型添加关联到PersonShift:
class Employee < ApplicationRecord belongs_to :person belongs_to :company # 关联到该员工在当前公司的活跃班次记录 has_many :active_person_shifts, ->(employee) { joins(:shift).where(shifts: { company_id: employee.company_id }, status: :ongoing) }, class_name: 'PersonShift', foreign_key: :person_id, primary_key: :person_id end
使用反向关联查询
date = Date.today # 获取所有拥有活跃班次的员工 active_employees = Employee.joins(:active_person_shifts) .where(shifts: { date: date }) .distinct # 统计数量 active_employee_count = active_employees.count
原理说明
这两种方案都是利用ActiveRecord关联的lambda条件,动态绑定关联模型之间的匹配规则(PersonID一致、公司ID与Shift所属公司一致),无需修改任何数据表结构,完全通过模型层的关联定义实现原生SQL的替代,既保持了代码的可读性,又符合遗留系统的约束。
内容的提问来源于stack exchange,提问作者Arvind
相关产品推荐
相关产品推荐

