急切加载不适用于 rails 中的 order() 子句
eager loading not working with order() clause in rails
我正在使用这个查询来获取我的数据
user = User.includes(:skills).order(user: :id)
它工作正常。但是当我尝试按字母顺序显示技能时,如下所示
user.skills.order(name: :asc)
它在日志中显示它进入数据库,因为 order()
是一个 activerecord
方法。似乎 eager loading
在这里失败了,因为如果它无论如何都必须进入数据库,那么使用预加载有什么意义。
谁能指导我这样做的好方法。
你可以使用这个:
user = User.includes(:skills).order(user: :id, name: :desc)
当您使用 .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
您可以使用内置方法实现灵活性 ActiveRecord::Associations::Preloader#preload。
它接受三个参数:
preload(records, associations, preload_scope = nil)
第一个参数接受 ActiveRecord::Base
记录或记录数组。
第二个是您希望预加载到第一个参数中指定的记录的一个或多个关联。
最后是 Hash
或 Relation
与协会合并。
使用第三个参数获取排序和预加载的关联:
users = User.order(user: :id)
ActiveRecord::Associations::Preloader.new.preload(
users,
:skills,
{ order: :name } # or Skill.order(:name)
)
我正在使用这个查询来获取我的数据
user = User.includes(:skills).order(user: :id)
它工作正常。但是当我尝试按字母顺序显示技能时,如下所示
user.skills.order(name: :asc)
它在日志中显示它进入数据库,因为 order()
是一个 activerecord
方法。似乎 eager loading
在这里失败了,因为如果它无论如何都必须进入数据库,那么使用预加载有什么意义。
谁能指导我这样做的好方法。
你可以使用这个:
user = User.includes(:skills).order(user: :id, name: :desc)
当您使用 .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
您可以使用内置方法实现灵活性 ActiveRecord::Associations::Preloader#preload。
它接受三个参数:
preload(records, associations, preload_scope = nil)
第一个参数接受 ActiveRecord::Base
记录或记录数组。
第二个是您希望预加载到第一个参数中指定的记录的一个或多个关联。
最后是 Hash
或 Relation
与协会合并。
使用第三个参数获取排序和预加载的关联:
users = User.order(user: :id)
ActiveRecord::Associations::Preloader.new.preload(
users,
:skills,
{ order: :name } # or Skill.order(:name)
)