gpt4 book ai didi

ruby-on-rails - ActiveRecord 急切加载多个 belongs_to 关联

转载 作者:数据小太阳 更新时间:2023-10-29 06:49:40 25 4
gpt4 key购买 nike

问题

我有以下 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, :business_car, :home_car)

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

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

最佳答案

试试这个:

> person_id = 1
> person = Person.includes(:favorite_car, :business_car, :home_car).where("people.id" = ?", person_id).references(:favorites_car, :business_car, :home_car)
> person[0].favorite_car

app/models/person.rb

class Person < ActiveRecord::Base
# columns: id, name, favorite_car_id, business_car_id, home_car_id
belongs_to :favorite_car, class_name: 'Car'
belongs_to :business_car, class_name: 'Car'
belongs_to :home_car, class_name: 'Car'
end

app/models/car.rb

class Car < ActiveRecord::Base
# columns: id, name
has_many :people
end

这有效的证明:

> Person.all
Person Load (0.3ms) SELECT "people".* FROM "people"
=> #<ActiveRecord::Relation [#<Person id: 1, favorite_car_id: 1, business_car_id: 2, home_car_id: 3, name: "Frankie", created_at: "2014-02-18 21:51:58", updated_at: "2014-02-18 21:53:34">]>

> Car.all
Car Load (0.3ms) SELECT "cars".* FROM "cars"
=> #<ActiveRecord::Relation [#<Car id: 1, name: "Mazda", created_at: "2014-02-18 21:52:16", updated_at: "2014-02-18 21:52:16">, #<Car id: 2, name: "Honda", created_at: "2014-02-18 21:52:20", updated_at: "2014-02-18 21:52:20">, #<Car id: 3, name: "BMW", created_at: "2014-02-18 21:52:24", updated_at: "2014-02-18 21:52:24">]>

> Person.includes(:favorite_car, :business_car, :home_car).where("people.id = ?", 1).references(:favorite_car, :business_car, :home_car)
SQL (0.4ms) SELECT "people"."id" AS t0_r0, "people"."favorite_car_id" AS t0_r1, "people"."business_car_id" AS t0_r2, "people"."home_car_id" AS t0_r3, "people"."name" AS t0_r4, "people"."created_at" AS t0_r5, "people"."updated_at" AS t0_r6, "cars"."id" AS t1_r0, "cars"."name" AS t1_r1, "cars"."created_at" AS t1_r2, "cars"."updated_at" AS t1_r3, "business_cars_people"."id" AS t2_r0, "business_cars_people"."name" AS t2_r1, "business_cars_people"."created_at" AS t2_r2, "business_cars_people"."updated_at" AS t2_r3, "home_cars_people"."id" AS t3_r0, "home_cars_people"."name" AS t3_r1, "home_cars_people"."created_at" AS t3_r2, "home_cars_people"."updated_at" AS t3_r3 FROM "people" LEFT OUTER JOIN "cars" ON "cars"."id" = "people"."favorite_car_id" LEFT OUTER JOIN "cars" "business_cars_people" ON "business_cars_people"."id" = "people"."business_car_id" LEFT OUTER JOIN "cars" "home_cars_people" ON "home_cars_people"."id" = "people"."home_car_id" WHERE (people.id = 1)
=> #<ActiveRecord::Relation [#<Person id: 1, favorite_car_id: 1, business_car_id: 2, home_car_id: 3, name: "Frankie", created_at: "2014-02-18 21:51:58", updated_at: "2014-02-18 21:53:34">]>

重要提示:Rails 会自动使用people 作为person 的复数形式。因此,当您创建一个Person 模型时,它会创建一个people 数据库表。

关于ruby-on-rails - ActiveRecord 急切加载多个 belongs_to 关联,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21864755/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com