当您有亲子关系时
class Parent < ActiveRecord::Base
has_many :children
end
class Child < ActiveRecord::Base
belongs_to :parent
end
> parent = parent.find(2)
Parent Load (0.6ms) SELECT `parents`.* FROM `parents` WHERE `parents`.`id` = 2 LIMIT 1
> children = parent.children
Child Load (1.4ms) SELECT `children`.* FROM `children` WHERE `children`.`parent_id` = 2
> children.to_a
Child Load (0.8ms) SELECT `children`.* FROM `children` WHERE `children`.`parent_id` = 2
> children.loaded?
=> true
> children.first.parent
Parent Load (0.7ms) SELECT `parents`.* FROM `parents` WHERE `parents`.`id` = 2 LIMIT 1
最后一行是杀死我的原因。为什么它会为父级命中数据库?似乎应该记住,因为孩子是通过父母加载的?
答案 0 :(得分:2)
解决方案是使用inverse_of
:
class Parent < ActiveRecord::Base
has_many :children, inverse_of: :parent
end
class Child < ActiveRecord::Base
belongs_to :parent, inverse_of: :children
end
> parent = Parent.find(foo)
# Fetches the parent
> children = parent.children
# Fetches all children
> children.first.parent
# No longer fetches the parent again
答案 1 :(得分:1)
belongs_to
关联具有一个名为inverse_of
的选项,如使用该选项,则会明确建立模型之间的双向关联,如API doc for belongs_to中所述。双向关联如何工作in this API doc。
基本上,如果Child
模型的关联写为belongs_to :parent, inverse_of: :parent
,则不会进行额外的查询。
请查看this blog以获得有关inverse_of
的工作方式的更多详细信息。它通过示例提供了很好的解释。
答案 2 :(得分:0)
从4.1开始,Rails自动检测关联的逆。
请参阅发行说明https://guides.rubyonrails.org/4_1_release_notes.html
在您的情况下,最后一行不是数据库的父级。实际的SQL查询获取了子级,因为当您在Rails控制台中访问该关联并且不实际使用该结果时,它不会被缓存。
parent = Parent.find(foo)
# Fetches the parent:
# Parent Load (0.3ms) SELECT "parents".* FROM "parents" WHERE ...
children = parent.children
# Fetches all children:
# Child Load (1.0ms) SELECT "children".* FROM "children" WHERE ...
# the association has not been cached
children.loaded? # => false
# Will fetch children again and again ...
children
# Fetches all children:
# Child Load (1.0ms) SELECT "children".* FROM "children" WHERE ...
children
# Fetches all children:
# Child Load (1.0ms) SELECT "children".* FROM "children" WHERE ...
# until you really use them:
children.to_a
children.loaded? # => true
children
# Does not hit the database now
因此,在您的情况下,执行数据库查询的是孩子。
parent = Parent.find(foo)
# Fetches the parent
children = parent.children
# Fetches all children
children.first.parent
# Fetches all children again, does not fetch parent as it is automatically inversed
child = children.first
# will not fetch the parent
child.parent