【问题标题】:Rails ActiveRecord eager_load with INNER JOINRails ActiveRecord eager_load 与 INNER JOIN
【发布时间】:2017-08-16 21:54:59
【问题描述】:

在一个大型 Rails 应用程序中,我注意到我们有一段代码会生成一个很大的 ActiveRecord::Relation。它在 .joins() 调用中使用自定义 SQL sn-ps——类似这样:

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

(注意JOINs 比这个例子中显示的更复杂;否则我显然只会做Foo.joins(bar: :baz)。)现在,在一些使用ActiveRecord::Relation 的地方,这很好。但在其他情况下,我们希望在 Foo 结果集上预先加载 bars 关联。

有没有办法做这样的事情:

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 两次

【问题讨论】:

  • 我在某种程度上取决于您如何使用它。如果您执行Foo.new(hash_of_stuff_i_plucked_from_the_db),则该记录将表现得像一条新记录,而不是从数据库中获取的记录。当涉及到回调以及将其传递给表单时会发生什么,这将产生意想不到的行为。
  • 代码joins("INNER JOIN bars ON foos.bar_id = bars.id") 也很奇怪,因为.joins 创建了一个LEFT INNER JOIN,你可以直接写成.joins(:bars).joins.eager_load 之间的主要区别在于 .joins 使用 INNER.eager_load OUTER
  • .select.pluck 之间的区别还在于 select 返回一个 ActiveRecord::Relation.pluck 返回一个数组(数组)。您可以使用.select 告诉 AR 究竟要采摘哪些列。例如@foo = Foo.select('foos.id, foos.baz, bars.id, bars.baz').joins(:bars) 只会加载命名的列。
  • 感谢 cmets @max。我知道你提到的事情,并对我的问题进行了一些澄清。

标签: ruby-on-rails ruby-on-rails-4 activerecord


【解决方案1】:

好吧,我最终重组了我的 foos 方法,以便它可以在那里简单地执行 includes。仍然对SELECTed 的所有字段不太满意,但我想这就是使用ActiveRecord 而不是Sequel 之类的东西。

【讨论】:

    猜你喜欢
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    • 2012-02-16
    • 2017-08-31
    • 2013-07-19
    • 2023-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多