Rails ActiveRecord eager_load с INNER JOIN
В большом приложении Rails я заметил, что у нас есть кусок кода, который производит большой ActiveRecord::Relation
, Он использует пользовательские фрагменты SQL в .joins()
звонки - что-то вроде этого:
def foos
Foo.
joins("INNER JOIN bars ON foos.bar_id = bars.id").
joins("INNER JOIN baz ON bars.baz_id = baz.id").
where(<some condition on bars>)
end
(Обратите внимание, что JOIN
s сложнее, чем показано в этом примере; иначе я бы, очевидно, просто сделал Foo.joins(bar: :baz)
.) Теперь, в некоторых местах, которые ActiveRecord::Relation
используется, это нормально. В других же мы хотим иметь bars
Ассоциация загружена на Foo
набор результатов.
Есть ли способ сделать что-то вроде этого:
def scope_with_bars_eager_loaded
foos.eager_load(:bars, using_existing_join_in_query: true)
end
Самое близкое, что я могу придумать, это:
def array_with_bars_eager_loaded
foos.pluck(<fields we need>).map do |fields|
bar = Bar.new(<get bar data from fields>)
# This of course doesn't behave as well as a Foo
# that we've loaded normally in regards to callbacks,
# fields we didn't SELECT, etc. But it's probably
# fine enough for this use-case (we're using this
# data to render a page).
Foo.new(<get foo data from fields>, bar: bar)
end
end
Что намного сложнее, а также не дает нам преимуществ быть ActiveRecord::Relation
, Любая помощь здесь будет оценена!
-
Замечания:
Любые предложения, которые избегают поведения Rails по умолчанию "загружать каждый столбец в базе данных, иногда несколько раз в одном запросе", особенно приветствуются (вот почему я использовал .pluck
вместо .select
, как .select
создает запросы, которые загружают все в Foo
даже если вы явно скажете это не делать). Пример: Foo.includes(:bar).where(bars: { condition: true }).select(:id)
выбирает каждый столбец в foos
и выбирает foos.id
дважды.
1 ответ
Ну, я закончил реструктуризацию foos
метод, чтобы он мог просто выполнить includes
там. Все еще не супер счастлив со всеми полями, являющимися SELECT
Эд, но я думаю, это то, что вы получаете за использование ActiveRecord
вместо чего-то вроде Sequel
,