我試圖避免加載的N + 1查詢問題,但它不工作。相關模型仍在單獨加載。爲什麼這個rails關聯在加載之後單獨加載?
下面是相關ActiveRecords和它們之間的關係:
class Player < ActiveRecord::Base
has_one :tableau
end
Class Tableau < ActiveRecord::Base
belongs_to :player
has_many :tableau_cards
has_many :deck_cards, :through => :tableau_cards
end
Class TableauCard < ActiveRecord::Base
belongs_to :tableau
belongs_to :deck_card, :include => :card
end
class DeckCard < ActiveRecord::Base
belongs_to :card
has_many :tableaus, :through => :tableau_cards
end
class Card < ActiveRecord::Base
has_many :deck_cards
end
class Turn < ActiveRecord::Base
belongs_to :game
end
和我使用的查詢是玩家的這種方法裏面:
def tableau_contains(card_id)
self.tableau.tableau_cards = TableauCard.find :all, :include => [ {:deck_card => (:card)}], :conditions => ['tableau_cards.tableau_id = ?', self.tableau.id]
contains = false
for tableau_card in self.tableau.tableau_cards
# my logic here, looking at attributes of the Card model, with
# tableau_card.deck_card.card;
# individual loads of related Card models related to tableau_card are done here
end
return contains
end
是否有與範圍呢?這個tableau_contains方法是在一個較大的循環中進行一些方法調用,我最初嘗試進行急切的加載,因爲有幾個地方這些相同的對象被循環和檢查。然後,我最終嘗試了上面的代碼,加載在循環之前,並且我仍然在日誌中的tableau_cards循環內看到針對Card的單個SELECT查詢。我可以在tableau_cards循環之前看到帶有IN子句的急切加載查詢。
編輯:下面修正循環與技巧從答案
EDIT3:下面較大,外環
EDIT2額外的信息增加了更多的細節循環與目標
這裏的大循環。這是一個觀察者內的after_save的
def after_save(pa)
turn = Turn.find(pa.turn_id, :include => :player_actions)
game = Game.find(turn.game_id, :include => :goals)
game.players.all(:include => [ :player_goals, {:tableau => [:tableau_cards => [:deck_card => [:card]]]} ])
if turn.phase_complete(pa, players) # calls player.tableau_contains(card)
for goal in game.goals
if goal.checks_on_this_phase(pa)
if goal.is_available(players, pa, turn)
for player in game.players
goal.check_if_player_takes(player, turn, pa)
... # loop through player.tableau_cards
end
end
end
end
end
end
這裏是在轉彎類的相關代碼:
def phase_complete(phase, players)
all_players_complete = true
for player in players
if(!player_completed_phase(player, phase))
all_players_complete = false
end
end
return all_players_complete
end
的for player in game.players
正在做另一個查詢加載的球員。它被緩存了,我的意思是它有日誌中的CACHE標籤,但我會認爲根本沒有查詢,因爲game.players應該已經加載到內存中了。
從目標模型的另一個片段:
class Goal < ActiveRecord::Base
has_many :game_goals
has_many :games, :through => :game_goals
has_many :player_goals
has_many :players, :through => :player_goals
def check_if_player_takes(player, turn, phase)
...
for tab_card in player.tableau_cards
...
end
end
我甚至需要爲玩家做查詢嗎?我已將for循環更改爲僅用於game.players中的播放器,並且它似乎正常工作。 – user26270 2010-05-03 20:08:38
對'players'的查詢迫切需要加載你需要的數據對象。隨後調用'game.players'返回緩存列表。你可以將兩個語句合併爲一個,但爲了便於閱讀,我寫了兩個。 – 2010-05-03 22:10:09
我在after_save中使用了'game.players.all(:include => [:player_goals,{:tableau => [:tableau_cards => [:deck_card => [:card]]]}])'''然後在'tableau_contains'中我使用了'tableau.tableau_cards.any?{| tc | tc.deck_card.card.id == card_id}',它仍然單獨加載tableau_contains中每個deck_card和卡片;我仔細檢查了玩家的tableau或tableau_cards關聯是否在任何地方被重置,但我找不到任何關聯,所以我仍然不知道爲什麼deck_cards和卡片會在其上面的熱切加載之後單獨被查詢 – user26270 2010-05-04 14:16:16