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

這就是我認爲的工作方式。急切加載主要用於通過一次性提取所有模型來對大型模型集合進行迭代,從而提高效率 - 如果您只是處理單個對象,則不會產生任何影響。