3

这个标题有点迟钝,所以这里有一个例子。假设我们有一个带有模型ShipPirate和的 Rails 3 应用程序Parrot。一艘船有_many 海盗,一艘海盗有_many 鹦鹉。

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 查询爆炸所必需的)。任何想法或建议将不胜感激。

4

2 回答 2

1
Ship.joins(pirates: :parrots).where('parrots.name LIKE ?', '%polly%').preload(pirates: :parrots)

需要导轨 3+

于 2014-09-02T07:06:04.643 回答
0

如果 INNER JOIN 是你正在寻找的,我想

Ship.includes(pirates: :parrots).where('parrots.name LIKE ?', '%polly%').joins(pirates: :parrots)

完成它。

于 2013-07-25T16:19:09.967 回答