【问题标题】:ActiveRecord: Nested association eager loading does not load grandchild object(s)ActiveRecord:嵌套关联急切加载不加载孙对象
【发布时间】:2014-11-14 12:00:51
【问题描述】:

我在 ActiveRecord 中有以下关系:Annotation 有许多 AnnotationGroups,每个都有一个 AnnotationNote(是的,注释在 AG 上,而不是在基础 Annos 上)。

Annotation.rb

has_many :annotation_groups, :dependent => :destroy

AnnotationGroup.rb

belongs_to :annotation
has_one :annotation_note, :foreign_key => 'annotation_group_id'

AnnotationNote.rb

belongs_to :annotation_group

现在,我正在尝试使用以下范围预先加载一系列注释、他们的组和他们的组的注释:

Annotation.rb

scope :flattened_by_group, ->(group_id) {
    includes(:annotation_groups => :annotation_note).where({
        'annotation_groups.group_id' => group_id
    })
}

这是应该触发急切加载的调用:

Annotation.flattened_by_group(group.id).as_json()

SQL 似乎确实提取了足够的数据来完成工作:

SQL (0.6ms)  SELECT "annotations"."id" AS t0_r0, (annotations cols trimmed) "annotation_groups"."id" AS t1_r0, (anno_groups cols trimmed) "annotation_notes"."id" AS t2_r0, "annotation_notes"."document_id" AS t2_r1, "annotation_notes"."annotation_group_id" AS t2_r2, "annotation_notes"."note" AS t2_r3, "annotation_notes"."addressed" AS t2_r4, "annotation_notes"."created_at" AS t2_r5, "annotation_notes"."updated_at" AS t2_r6 FROM "annotations" 
LEFT OUTER JOIN "annotation_groups" ON "annotation_groups"."annotation_id" = "annotations"."id" 
LEFT OUTER JOIN "annotation_notes" ON "annotation_notes"."annotation_group_id" = "annotation_groups"."id" 
WHERE "annotation_groups"."group_id" = 81

这是as_json 代码,我开始遇到问题:

 def as_json(opts={})
    anno_group = annotation_groups[0]
    opts.merge({:skip_groups => true})
    canonical(opts).merge({
      'document_id'         => document_id,
      'account_id'          => account_id,
      'organization_id'     => organization_id,
      'annotation_group_id' => anno_group.id,
      'approved_count'      => anno_group.approved_count,
      'qa_approved_by'      => anno_group.qa_approved_by,
      'qa_note'             => anno_group.annotation_note ? anno_group.annotation_note.note : nil
    })
  end

annotation_groups[0] 执行时,不会触发任何查询,这向我表明预加载有效。但是,在anno_group.annotation_note 检查(或其任何变体)中,每次都会执行一个新查询,获取该特定 annotation_group 的注释(即使只是检查对象是否为 nil)。

为什么是子对象 (AnnotationGroup) 被急切加载,而不是孙对象 (AnnotationNote),即使它的字段在来自 includes 子句的查询中正确返回?

======更新=======

从遵循 Rails 急切加载逻辑,我怀疑问题源于那些与数据库中的任何内容都不匹配的记录(因此 AnnotationNote 没有数据,因此没有创建它)。有没有办法在不向数据库发起另一个查询的情况下检查这个 nil 状态?

【问题讨论】:

  • 顺便说一句,我的 Rails 版本是 4.1.0,以防万一。我正在搜索 Rails 的问题跟踪器,看看是否在 4.1.0 和当前版本之间修复了类似的问题,但到目前为止还没有找到任何东西。
  • 我对 Rails 4.1.6 进行了临时更新并试了一下,它仍然遵循相同的逻辑。

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


【解决方案1】:

因此,从我对 Rails 逻辑的挖掘中发现,如果从表中连接的行的 id 为NULL,则“急切加载”不会为关联创建空白对象。检查对象是否是通过在关联上使用.nil? 创建的,将运行查询来查找它,从而破坏了预加载的目的。

因为它是has_one 关系,所以检查它是否已加载并没有我能找到的花哨功能,就像loaded?has_many 关系所做的那样。所以我最终做的是检查AnnotationGroup 对象的annotation_cache 中是否存在annotation_note。相关代码更改如下:

'qa_note' => anno_group.association_cache.keys.include?(:annotation_note) ? anno_group.annotation_note.note : nil

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-01
    • 2017-08-28
    相关资源
    最近更新 更多