我有以下模型:游戏和选择。 Game 和 Pick 之间存在一对多关联。第三种模型称为玩家,玩家有很多选择。
Player 类中有一个方法可以查找给定游戏的选择,如果不存在则创建一个新游戏。
class Player < ActiveRecord::Base
has_many :picks
def pick_for_game(game)
game_id = game.instance_of?(Game) ? game.id : game
picks.find_or_initialize_by_game_id(game_id)
end
end
我想急切地加载每个选择的游戏。但是,如果我这样做,
picks.find_or_initialize_by_game_id(game_id, :include => :game)
它首先在运行此查询时获取选择(该方法运行多次),然后在访问每个选择时获取游戏。如果我将 default_scope 添加到 Pick 类,
class Pick < ActiveRecord::Base
belongs_to :game
belongs_to :player
default_scope :include => :game
end
它仍然会为每个选择生成 2 个选择语句,但现在它会在选择后立即加载游戏,但它仍然不会像我期望的那样进行连接。
Pick Load (0.2ms) SELECT "picks".* FROM "picks" WHERE "picks"."game_id" = 1 AND ("picks".player_id = 1) LIMIT 1
Game Load (0.4ms) SELECT "games".* FROM "games" WHERE ("games"."id" = 1)
I have the following models: Game and Pick. There's a one to many association between Game and Pick. There's a third model called Player, a Player has many Picks.
There's a method in the Player class that finds a pick for a given game or creates a new one if it doesn't exist.
class Player < ActiveRecord::Base
has_many :picks
def pick_for_game(game)
game_id = game.instance_of?(Game) ? game.id : game
picks.find_or_initialize_by_game_id(game_id)
end
end
I want to eager load the games for each pick. However if I do
picks.find_or_initialize_by_game_id(game_id, :include => :game)
It first fetches the picks when this query is run (the method is run multiple times), then fetches the games as each pick is accessed. If I add a default_scope to the Pick class
class Pick < ActiveRecord::Base
belongs_to :game
belongs_to :player
default_scope :include => :game
end
It still generates 2 select statements for each pick, but now it loads the game right after the pick, but it still doesn't do a join like I'm expecting.
Pick Load (0.2ms) SELECT "picks".* FROM "picks" WHERE "picks"."game_id" = 1 AND ("picks".player_id = 1) LIMIT 1
Game Load (0.4ms) SELECT "games".* FROM "games" WHERE ("games"."id" = 1)
发布评论
评论(2)
首先,
查找不支持
include
或将
作为参数。 (正如Mipsy所说,寻找支持include
,因为它与以后加载相同的查询数量。协会,所以
大致相当于这样做:
我说大致相当于,因为前者具有
o(1)
(实际上是两个)查询,而后者是o(n)
查询,其中n
是人数。但是,加入只是一个查询,但是连接的缺点是您不能总是使用检索到的数据来更新模型。要加入您会做的:
您可以在.
总而言之,加入并不是因为它没有加载关联而急切地加载,而是一次将两个数据加载在一起。我意识到这两者之间有一条奇怪的细线,但是热切的加载是抢先获得其他数据,但是您以后不会通过JOIN获得该数据,否则您已经在原始查询中获得了数据!希望这是有道理的。
First,
find
doesn't support havinginclude
orjoin
as a parameter. (As mipsy said, it doesn't make sense for find to supportinclude
as it would be the same number of queries as loading it later.)Second,
include
eagerly loads the association, so something likeis roughly equivalent to doing:
I say roughly equivalent to because the former has
O(1)
(really two) queries whereas the latter isO(n)
queries, wheren
is the number of people.A join, however, would be just one query, but the downside of a join is you can't always use the retrieved data to update the model. To do a join you would do:
You can read more on joining tables in the Rails Guide.
To sum up, joining isn't eagerly loading because it's not loading the association, it's loading both pieces of data together at once. I realize there's a weird fine line between the two, but eagerly loading is getting other data preemptively, but you wouldn't be getting that data later via a join, or you'd have already gotten it in your original query! Hope that makes sense.
我认为这就是它的工作方式。急切的加载主要用于使大量模型的迭代一次通过一次获取所有物体的效率 - 如果您只是处理一个对象,则不会有任何区别。
This is the way it's meant to work, I think. Eager loading is primarily used to make iterations over large collections of models more efficient by fetching them all at once-- it won't make any difference if you're just dealing with a single object.