4

我有以下模型:游戏和挑选。 Game和Pick之间有一对多的联系。还有第三种模式叫玩家,玩家有很多精选。Rails ActiveRecord帮手查找方法不急切加载关联

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添加到匹克类

class Pick < ActiveRecord::Base 
    belongs_to :game 
    belongs_to :player 
    default_scope :include => :game 
end 

它仍然会为每个选择2条SELECT语句,但现在它挑右后加载游戏,但它仍然没有做加盟像我期待。

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) 
+0

你为什么期望它做一个连接?这不是你要告诉它做的。 – 2011-04-02 00:41:38

+0

@Andrew,所以':include'和做连接不一样?我来自NHibernate的背景,所以我期待它通过一个连接完成一个调用,并且迫切地加载关联的实体。 – Vadim 2011-04-02 02:31:12

回答

2

首先,find不支持将includejoin作为参数。 (正如mipsy说,它没有任何意义的发现支持include因为它以后相同数量的查询,加载它。)

其次,include急切地加载的关联,所以像

Person.includes(:company) 

大致相当于做:

Person.all.each { |person| Company.find(person.company_id) 

我说大致相当于,因为前者O(1)(实际上是两个)查询,而LA tter是O(n)查询,其中n是人数。

但是,连接只会是一个查询,但连接的缺点是您无法始终使用检索到的数据来更新模型。要做一个加入,你会这样做:

Person.join(:companies) 

你可以在joining tables in the Rails Guide阅读更多。

总之,加入并不急于加载,因为它没有加载关联,它一次加载两个数据。我意识到两者之间存在一条奇怪的细线,但是急切地加载是先发制人的获取其他数据,但以后通过连接不会获得这些数据,或者您已经将它用原始查询获得了!希望这是有道理的。

+0

所以说清楚一点,Person.join(:companies)这个语句返回Person对象与加载的公司? – Vadim 2011-04-04 03:47:41

+0

'Person.join(:companies)'将运行查询'SELECT people。* FROM people INNER JOIN companies on people.company_id = companies.id' – 2011-04-04 04:14:36

+0

[This question and its answers](http://stackoverflow.com/问题/ 1208636/rails-include-vs-joins)可能对你有帮助。 – 2011-04-04 04:16:55

0

这就是我认为的工作方式。急切加载主要用于通过一次性提取所有模型来对大型模型集合进行迭代,从而提高效率 - 如果您只是处理单个对象,则不会产生任何影响。