JOIN ON …和在ActiveRecord中加载关联时的条件

请注意,这不是关于向关联添加WHERE条件的问题,而是关于在使用eager_load时如何更改JOIN子句的相当高级的问题。

可以说我有这些模型

class Parent has_many :children have_many :grades, through: :children end class Child belongs_to :parent end class Grade belongs_to :child end 

所以要急切地加载我会做的父母:

 Parent.eager_load(:grades) 

但如果我想要所有的父母 – 但只是渴望加载最高得分,如下:

 LEFT OUTER JOIN grades ON grades.child_id = children.id AND grades.level = 'A+' 

我尝试过使用includes(:children).joins("LEFT OUTER JOIN grades ON grades.child_id = children.id AND grades.level = 'A+'")但由于Rails没有构建关联对象,因此会引起额外的查询为每个父母。

我没有找到任何关于将eager_load与自定义SQL字符串一起使用的eager_load ,并且已经挖掘了源代码而没有获得任何更好的知识。

如果我是对的,你只想加载关联的子集。 好吧,为了做到这一点,你需要超越铁轨。 您基本上可以创建另一个关联,例如“highest_grade”,以使用ruby lambda中的where子句获取级别为A +的成绩。 这可以通过使用以下代码片段来实现

 class Parent has_many :children has_many :grades, through: :children has_many :highest_grade, ->{where(level: 'A+')}, class_name: "Grade", through: :children end 

现在您需要急切加载highest_grade关联。

  Parent.eager_load(:highest_grades) 

这基本上会加载所有父母以及只有等级为A +的成绩。

它会生成以下查询。

  SQL (0.3ms) SELECT `parents`.`id` AS t0_r0, `parents`.`created_at` AS t0_r1, `parents`.`updated_at` AS t0_r2, `grades`.`id` AS t1_r0, `grades`.`child_id` AS t1_r1, `grades`.`created_at` AS t1_r2, `grades`.`updated_at` AS t1_r3, `grades`.`level` AS t1_r4 FROM `parents` LEFT OUTER JOIN `children` ON `children`.`parent_id` = `parents`.`id` LEFT OUTER JOIN `grades` ON `grades`.`child_id` = `children`.`id` AND `grades`.`level` = ' 

如果你想了解这是如何工作的。 请使用此链接作为参考

编辑

这并不能解决所述问题。


您不能通过调用eager_load来改变生成的JOIN。 WHERE子句是您唯一的选项,它与JOIN上的条件具有完全相同的效果。 就在这里,即使你不想要它:

 Parent.eager_load(:grades).where("grades.level = 'A+'")