我有一个子组件模型,可以属于其他子组件。我的模型看起来像这样:
class SubComponent < ApplicationRecord
belongs_to :parent, class_name: "SubComponent", foreign_key: "parent_sub_component_id", optional: true
has_many :child_sub_components, class_name: "SubComponent", foreign_key: "parent_sub_component_id"
validates_presence_of :name
end
此模型非常简单,它有name
字段和parent_sub_component_id
,顾名思义是另一个id
的{{1}}。
我想生成一个返回所有SubComponent
(包含SubComponents
,id
和name
)的查询,但也包含实际内容它的名称是parent_sub_component。
这看起来应该很简单,但对于我的生活,我无法弄清楚如何去做。我希望在数据库中完成此查询,而不是在Ruby中执行每个循环或类似的事情。
编辑:
我希望输出看起来像这样:
parent_sub_component_id
答案 0 :(得分:1)
如果您使用each
:
includes
循环有效地执行此操作
SubComponent.all.includes(:parent).each do |comp|
comp.parent.name # this gives you the name of the parent
end
includes
做了什么预取指定的关联。也就是说,ActiveRecord将查询所有子组件,然后在单个查询中也拉下这些子组件的所有父组件。当您随后在循环中访问comp.parent
时,已经加载了关联的父级,因此这不会导致所谓的 N + 1查询。
AR将自动为您生成的查询将如下所示:
SELECT `subcomponents`.* FROM `subcomponents`
SELECT `subcomponents`.* FROM `subcomponents` WHERE `subcomponents`.`id` IN (1, 3, 9, 14)
如果您需要在where
条件下使用父级名称,includes
将无效,您必须使用joins
来实际生成SQL {{1 }}
答案 1 :(得分:0)
这是未经测试的,但是应该让你从正确的方向开始,你可以通过做类似
的方式在Arel中做到这一点def self.execute_query
parent_table = Arel::Table.new(:sub_component).alias
child_table = Arel::Table.new(:sub_component)
child_table.join(parent_table, Arel::Nodes::OuterJoin).on(child_table[:parent_sub_component_id].eq(parent_table[:id]).project(child_table[:id], child_table[:name], parent_table[:id], parent_table[:name])
end
这会产生类似
的查询SELECT "sub_component"."id", "sub_component"."name", "sub_component_2"."id", "sub_component_2"."name" FROM "sub_component" LEFT OUTER JOIN "sub_component" "sub_component_2" ON "sub_component"."parent_sub_component_id" = "sub_component_2"."id"
通过查看Rails/Arel并且可能需要一些工作,这只是我的头脑,但查询看起来我期待什么,这应该让你去。