这个标题有点迟钝,所以这是一个例子。假设我们有一个包含模型Ship
,Pirate
和Parrot
的Rails 3应用。一艘船上有很多海盗,一个海盗有很多鹦鹉。
Ship.includes(pirates: :parrots).where('parrots.name LIKE ?', '%polly%')
这会使至少有一名海盗的船只至少有一只鹦鹉,其名字就像是“polly”。我还希望为这些船只急切地加载所有海盗和鹦鹉 ......但实际上只有配有鹦鹉的海盗才会急切加载,其中只有匹配的鹦鹉渴望加载。生成的SQL是这样的:
SELECT ships.id AS t0_r0, ships.name AS t0_r1, pirates.id AS t1_r0, pirates.name AS t1_r1, parrots.id AS t2_r0, parrots.name AS t2_r1 FROM ships LEFT OUTER JOIN pirates ON pirates.ship_id = ships.id LEFT OUTER JOIN parrots ON parrots.pirate_id = pirates.id WHERE (parrots.name LIKE '%polly%')
在没有条件的情况下执行Ship.includes(pirates: :parrots)
时,ActiveRecord会生成一组更接近我想要的查询:
SELECT ships.* FROM ships
SELECT pirates.* FROM pirates WHERE pirates.ship_id IN (ship IDs from previous query)
SELECT parrots.* FROM parrots WHERE parrots.pirate_id IN (pirate IDs from previous query)
如果我可以以某种方式更改第一个查询以使用第一个示例中的SQL,那么它将完全符合我的要求:
SELECT ships.* FROM ships LEFT OUTER JOIN pirates ON pirates.ship_id = ships.id LEFT OUTER JOIN parrots ON parrots.pirate_id = pirates.id WHERE (parrots.name LIKE '%polly%')
SELECT pirates.* FROM pirates WHERE pirates.ship_id IN (ship IDs from previous query)
SELECT parrots.* FROM parrots WHERE parrots.pirate_id IN (pirate IDs from previous query)
但是我不知道有什么方法可以让ActiveRecord这样做,或者自己做任何方式并“手动”连接预先加载(这在我的情况下是必要的,以避免N + 1查询爆炸)。任何想法或建议将不胜感激。
答案 0 :(得分:1)
Ship.joins(pirates: :parrots).where('parrots.name LIKE ?', '%polly%').preload(pirates: :parrots)
需要rails 3 +
答案 1 :(得分:0)
如果您正在寻找INNER JOIN,我想
Ship.includes(pirates: :parrots).where('parrots.name LIKE ?', '%polly%').joins(pirates: :parrots)
完成它。