gpt4 book ai didi

ruby-on-rails - Rails 5 Eager load 然后 find_by

转载 作者:行者123 更新时间:2023-12-04 16:04:02 25 4
gpt4 key购买 nike

我有如下三个模型:

class Parent < ApplicationRecord
has_many :children
has_many :assets
end

class Child < ApplicationRecord
belongs_to :parent
end

class Asset < ApplicationRecord
belongs_to :parent
end

现在我需要通过 parent 找出属于 child 的 Assets 。并且“ Assets ”具有 Assets 类型列。所以我需要做这样的事情

Parent.first.children.each do |child|
child.parent.assets.find_by(asset_type: "first").asset_value
end

如何避免 N+1 查询?

rails :5.1.6

ruby :2.3.4

最佳答案

第一个问题是添加 find_by总是执行另一个查询,无论您预加载了什么(至少从 Rails 4 开始,我怀疑它已经改变了) .这是因为 find_by 被实现来生成更多的 SQL。如果要预加载,可以使用 find 代替,只要每个父级的 Assets 数量不高就很好,但如果有很多很多 Assets 和/或它们是会占用大量内存的大型对象(请参阅下面的注释了解替代解决方案)。

您可以像这样预加载 Assets :

parent.children.preload(:parent => :assets) each do |child|
# Will not execute another query
child.parent.assets.find{ |asset| asset.asset_type == "first" }

或者,您可以声明一个 has_many :through 关联:

class Child < ActiveRecord::Base
belongs_to :parent
has_many :assets, through: :parent
...
end

那你就可以了

parent.children.preload(:assets).each do |child|
# Will not execute another query
child.assets.find { |asset| asset.asset_type == "first" }

如果你想在 db 层而不是 ruby​​ 中执行 find,你可以定义一个作用域关联:

class Parent < ActiveRecord::Base
has_one :first_asset, ->{ where asset_type: "first" }
...
end

这样你可以 preload(:parent => :first_asset) 代替。

关于ruby-on-rails - Rails 5 Eager load 然后 find_by,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52762015/

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