【问题标题】:eager loading not working with order() clause in rails急切加载不适用于rails中的order()子句
【发布时间】:2017-09-25 23:54:49
【问题描述】:

我正在使用此查询来获取我的数据

user = User.includes(:skills).order(user: :id)

它工作正常。但是当我尝试按字母顺序显示技能时,如下所示

user.skills.order(name: :asc)

它在日志中显示它进入数据库,因为order()activerecord 方法。似乎eager loading 在这里失败了,因为如果无论如何都必须进入数据库,那么使用急切加载有什么意义。

谁能指导我什么是这样做的好方法。

【问题讨论】:

  • 只是一个建议,你能分享你的日志吗?

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


【解决方案1】:

当您使用 .includes 急切加载关联记录时,您应该按原样访问关联。否则,如果向关联中添加更多查询条件,则会导致新的数据库查询。

您可以通过多种方式订购相关的预先加载的记录。

1.将订单条件添加到主范围。

user = User.includes(:skills).order("users.id, skills.name ASC")

在这种情况下,它不会像include 方法那样工作,默认情况下会进行两次查询。将使用“LEFT OUTER JOIN”执行一个查询以获取相关记录。这相当于使用eager_load 方法而不是includes

user = User.eager_load(:skills).order("users.id, skills.name ASC")

2。定义时将订单条件添加到关联中。

在这种情况下,每当您访问关联时,关联的记录将始终按名称排序。

class User < ActiveRecord::Base
  has_many :skills, -> { order(:name) }
end

3.创建另一个具有所需顺序的关联,仅在此特定情况下使用。

这可以让您避免在主关联 skills 上出现不必要的条件。

class User < ActiveRecord::Base
  has_many :skills_ordered_by_name, -> { order(:name) }, class_name: "Skill"
end

# usage
users = User.includes(:skills_ordered_by_name)

users.each do |user|
  # access eager loaded association
  user.skills_ordered_by_name
end

4.设置关联模型的默认顺序。

这将导致条件应用于与关联模型相关的每个关联和查询。

class Skill < ActiveRecord::Base
  default_scope { order(:name) }
end

5.使用 Ruby 代码(不是 ActiveRecord 查询方法)对预先加载的记录进行排序

当要排序的记录不多时,这种方法是合适的。

users = User.includes(:skills)

users.each do |user|
  # sorting with Ruby's 'sort_by' method
  user.skills.sort_by(&:name)

  # or something like
  user.skills.sort { |one, another| one.name <=> another.name }
end

【讨论】:

  • 感谢您的详细回答。但除了 eager_load 没有任何效果。为什么
  • 一切正常。是什么让您认为某些东西不起作用:错误、额外的数据库查询、错误的顺序或其他什么?
  • 没有错误,但对结果没有影响。我实现了所有这些来检查差异
  • 如果您愿意,您可以在某处发布您的代码并给我链接。我去看看。
【解决方案2】:

您可以通过使用内置方法ActiveRecord::Associations::Preloader#preload 来实现灵活性。

它接受三个参数:

preload(records, associations, preload_scope = nil)

第一个参数接受ActiveRecord::Base 记录或记录数组。 其次是您希望预加载到第一个参数中指定的记录的一个或多个关联。 最后是与关联合并的HashRelation

使用第三个参数来获得排序和预加载的关联:

users = User.order(user: :id)

ActiveRecord::Associations::Preloader.new.preload(
  users,
  :skills,
  { order: :name } # or Skill.order(:name)
)

【讨论】:

    【解决方案3】:

    你可以用这个:

    user = User.includes(:skills).order(user: :id, name: :desc)
    

    【讨论】:

      猜你喜欢
      • 2022-01-09
      • 2020-09-12
      • 2021-10-08
      • 1970-01-01
      • 2018-01-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多