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

发布于 2024-10-29 03:58:18 字数 956 浏览 0 评论 0 原文

我有以下模型:游戏和选择。 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

国际总奸 2024-11-05 03:58:18

首先, 查找不支持 include 作为参数。 (正如Mipsy所说,寻找支持 include ,因为它与以后加载相同的查询数量

。协会,所以

Person.includes(:company)

大致相当于这样做:

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

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

但是,加入只是一个查询,但是连接的缺点是您不能总是使用检索到的数据来更新模型。要加入您会做的:

Person.join(:companies)

您可以在.

总而言之,加入并不是因为它没有加载关联而急切地加载,而是一次将两个数据加载在一起。我意识到这两者之间有一条奇怪的细线,但是热切的加载是抢先获得其他数据,但是您以后不会通过JOIN获得该数据,否则您已经在原始查询中获得了数据!希望这是有道理的。

First, find doesn't support having include or join as a parameter. (As mipsy said, it doesn't make sense for find to support include as it would be the same number of queries as loading it later.)

Second, include eagerly loads the association, so something like

Person.includes(:company)

is roughly equivalent to doing:

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

I say roughly equivalent to because the former has O(1) (really two) queries whereas the latter is O(n) queries, where n 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:

Person.join(:companies)

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.

勿忘初心 2024-11-05 03:58:18

我认为这就是它的工作方式。急切的加载主要用于使大量模型的迭代一次通过一次获取所有物体的效率 - 如果您只是处理一个对象,则不会有任何区别。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文