Rails ActiveRecord帮助器查找方法不急于加载关联

时间:2011-04-02 00:35:32

标签: ruby-on-rails ruby-on-rails-3 activerecord eager-loading

我有以下型号:游戏和挑选。 Game和Pick之间存在一对多关联。还有第三个名为Player的模型,玩家有很多选择。

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)

2 个答案:

答案 0 :(得分:2)

首先,find不支持将includejoin作为参数。 (正如mipsy所说,找到支持include没有意义,因为它与后来加载它的查询数量相同。)

其次,include急切加载关联,如

Person.includes(:company)

大致相当于:

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

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

然而,连接只是一个查询,但是连接的缺点是您不能总是使用检索到的数据来更新模型。要进行加入,您可以这样做:

Person.join(:companies)

您可以在joining tables in the Rails Guide上阅读更多内容。

总而言之,加入并不是急切加载,因为它没有加载关联,它正在同时加载两个数据。我意识到两者之间有一个奇怪的细线,但是急切地加载是抢先获得其他数据,但是你以后不会通过连接获得这些数据,或者你已经在原始查询中获得了它!希望这是有道理的。

答案 1 :(得分:1)

我认为这就是它的工作方式。渴望加载主要用于通过一次性获取它们来使大型模型集合的迭代更加高效 - 如果您只处理单个对象,它将不会有任何区别。