使用 Rails 查询急切加载

Posted

技术标签:

【中文标题】使用 Rails 查询急切加载【英文标题】:Eager Loading with Rails Query 【发布时间】:2014-10-23 18:44:33 【问题描述】:

在我的 Rails 应用中,项目有很多步骤,步骤可以有问题

我想编写一个方法来检查项目是否有任何问题,并返回带有问题的步骤的 id。

目前,我的 project.rb

中有以下内容
 def step_with_question
    question_step = ""
    steps.order(:published_on).each do |step|
      if step.question
        question_step = step.id
      end
    end
    return question_step
  end

但我认为这是低效的,并且认为通过预先加载可能有更快的方法来执行此操作(这会为项目中的每个步骤创建一个查询)。有人对如何做到这一点有建议吗?

【问题讨论】:

【参考方案1】:

您可以使用joins 只返回关联的:steps,它们实际上与它们有:questions 关联:

@project = Project.joins(steps: :questions).order('steps.published_on').find(id)

此查询将仅返回实际具有相关问题的项目步骤。您现在可以安全地遍历步骤记录并返回或使用step.id

@project.steps.each do |step|
  question_step = step.id
  # do something with the question_step
end

【讨论】:

【参考方案2】:

我不明白你的代码究竟做了什么,但是如果你想从一个步骤访问一个问题,你可以使用方法includes

project = Project.find(id) # Get a product just to show how it works
# To tell Rails to make a single query when you want to
# access the questions, do something like this:
steps_with_questions = project.steps.includes(:question)

这样,当您尝试访问一个问题时,它就会被加载。

使用这些的最佳方法是为step.rb 编写一个作用域,如下所示:

scope :with_questions, lambda  includes :questions 

现在你只需要调用:

project.steps.with_questions

使代码更易于阅读。

编辑:您的代码如下所示:(没有我之前提到的范围)

 def step_with_question
    question_step = ""
    steps.order(:published_on).includes(:question).each do |step|
      if step.question
        question_step = step.id
      end
    end
    return question_step
  end

【讨论】:

你可以考虑 has_many :through 将问题与项目联系起来

以上是关于使用 Rails 查询急切加载的主要内容,如果未能解决你的问题,请参考以下文章

优化 Rails 急切加载查询以查找所有

实施急切加载以停止 N+1 - Rails

急切加载与加入获取相同吗?

如何使用急切加载来查询尽可能少的数据?

在 EFCore 急切加载 LINQ 查询中,如何在 ThenInclude() 表达式中引用***实体?

使用 Laravel 将两个模型合并到一个分页查询中,并带有急切加载的关系