Rails ActiveRecord помощник метод поиска не стремится загрузки ассоциации - PullRequest
4 голосов
/ 02 апреля 2011

У меня есть следующие модели: Game и Pick. Между Game и Pick существует связь один ко многим. Есть третья модель, которая называется Player, у игрока много Picks.

В классе 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 ]

2 голосов
/ 02 апреля 2011

Во-первых, find не поддерживает наличие include или join в качестве параметра.(Как сказал Mipsy, для find не имеет смысла поддерживать include, поскольку это будет то же количество запросов, что и при его последующей загрузке.)

Во-вторых, include охотно загружает ассоциацию, поэтомучто-то вроде

Person.includes(:company)

примерно эквивалентно выполнению:

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

Я говорю примерно эквивалентно тому, что первый имеет O(1) (на самом деле два) запроса, тогда какпоследний - O(n) запросов, где n - количество людей.

Соединение, однако, будет одним запросом, но недостатком объединения является то, что вы не всегда можете использовать извлеченныеДанные для обновления модели.Чтобы выполнить объединение, вы должны сделать:

Person.join(:companies)

Подробнее о объединении таблиц вы можете прочитать в Руководстве по Rails .

Подводя итог, присоединение не является стремительнымзагрузка, потому что она не загружает ассоциацию, она загружает обе части данных одновременно.Я понимаю, что между ними есть странная тонкая грань, но при быстрой загрузке происходит получение других данных с опережением, но вы не получите эти данные позже через объединение, иначе вы уже получили бы их в исходном запросе!Надеюсь, что это имеет смысл.

1 голос
/ 02 апреля 2011

Думаю, так оно и должно работать.Стремительная загрузка в основном используется для повышения эффективности итераций в больших коллекциях моделей за счет их одновременной загрузки - это не имеет значения, если вы работаете только с одним объектом.

...