加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

ruby-on-rails – ActiveRecord渴望加载多个belongs_to关联

发布时间:2020-12-16 19:14:26 所属栏目:百科 来源:网络整理
导读:问题 我有以下ActiveRecord模型: class Person belongs_to :favourite_car,class_name: 'Car' belongs_to :business_car,class_name: 'Car' belongs_to :home_car,class_name: 'Car'end 当我想访问所有这三个关联时,它会生成三个选择查询: SELECT * FROM c
问题

我有以下ActiveRecord模型:

class Person
  belongs_to :favourite_car,class_name: 'Car'
  belongs_to :business_car,class_name: 'Car'
  belongs_to :home_car,class_name: 'Car'
end

当我想访问所有这三个关联时,它会生成三个选择查询:

SELECT * FROM cars WHERE cars.id = ?

这基本上是N 1问题.

理想情况下,我希望它只生成一个表单查询

SELECT * FROM cars WHERE cars.id IN (?,?,?)

可能的方案

我可以把它移到has_many:through => :join_table与连接表中的列关联以指示关联类型是什么,然后使用includes([:join_table,:cars])来急切加载关联.但是,在这种情况下,它只将3个查询减少到2,并引入了一个额外的表.

另一种可能的方法

另一种可能的解决方案是手动加载关联,如下所示:

module EagerLoader
  def eager_load(*associations)
    reflections = associations.map { |association| self.class.reflections[association.to_sym] }
    raise 'Not all are valid associations' if reflections.any?(&:nil?)

    reflections.group_by { |association| association.klass }.each do |klass,reflections|
      load_associations(klass,reflections)
    end

    self

  end

private

  def load_associations(klass,reflections)

    primary_key = klass.primary_key

    ids = reflections.map { |reflection| public_send(reflection.foreign_key) }

    records = klass.where(id: ids)


    reflections.each_with_index do |reflection,i|
      record = records.find do |record|
        record.public_send(primary_key) == ids[i]
      end

      public_send("#{reflection.name}=",record)
    end

  end


end

我测试了它,它的工作原理.

class Person
  include EagerLoader
end

Person.find(2).eager_load(:favorite_car,:business_car,:home_car)

但是,当你想要做的事情时,这仍然无法帮助你

Person.includes(:favourite_car,:home_car)

例如,在人员索引页面上.这会将查询数量从3N减少到4,但实际上只需要2个.

有没有更好的解决方案来解决这个问题?

解决方法

关于手动Eager加载有一篇很棒的帖子.

http://mrbrdo.wordpress.com/2013/09/25/manually-preloading-associations-in-rails-using-custom-scopessql/

我想这就是你一直在寻找的东西:

owners = People.all
association_name = :photos

owners.each do |owner|
   record = whatever_you_want

   association = owner.association(association_name)
   association.target = record
   association.set_inverse_instance(record)
end

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读