我的开发环境是在Rails 4.1和postgresql
上我有3个带有has_many关系的模型:
class Item < ActiveRecord::Base
has_many :item_parts
has_many :parts, through: :item_parts
end
class Part < ActiveRecord::Base
has_many :item_parts
has_many :items, through: :item_parts
end
class ItemPart < ActiveRecord::Base
belongs_to :item
belongs_to :part
end
item_parts连接表有一个unit_count属性,用于跟踪该项目包含的部分。
当在视图中迭代特定项的所有部分时,我还需要从连接表中获取unit_count值。
这给我提出了n + 1查询问题。
我试图加载加入表:
item.parts.includes(:item_parts)
ItemPart Load (0.5ms) SELECT "item_parts".* FROM "item_parts" WHERE "item_parts"."part_id" IN (24, 12, 3, 26)
但是在我做完之后:
part.item_parts.where(item_id: item.id).first.unit_count
我得到了每个部分的sql查询;急切的装载没有工作
ItemPart Load (0.5ms) SELECT "item_parts".* FROM "item_parts" WHERE "item_parts"."part_id" = $1 AND "item_parts"."item_id" = $2 [["part_id", 24], ["item_id", 18]]
有什么建议吗?
答案 0 :(得分:1)
我希望这是因为你正在使用&#34; count&#34;方法,根据:
&#34;在对象生命周期内没有存储在内部,这意味着,每次调用此方法时,都会再次执行SQL查询&#34;
尝试使用 .length 或 .size 方法。
注意:(引用文章)
答案 1 :(得分:1)
点击此链接后,我找到了针对我案例的解决方案:Rails Eager Loading and where clause
我不知道Active Record Query Method:选择(http://apidock.com/rails/v4.1.8/ActiveRecord/QueryMethods/select)
似乎我无法急切加载连接表,因为在包含item_parts之后我在项目部分的迭代过程中使用了where子句。
似乎where子句每次在迭代期间使用时都会对db进行新的查询。
相反,select方法不会每次都访问db,而是处理加载到内存中的Active Record集合。
所以我改变了这个:
item.parts.includes(:item_parts)
part.item_parts.where(item_id: item.id).first.unit_count
用这个:
item.parts.includes(:item_parts)
part.item_parts.select{|item_part| item_part.item_id == item.id}.first.unit_count
然后我有一个查询来加载item_parts:
ItemPart Load (0.5ms) SELECT "item_parts".* FROM "item_parts" WHERE "item_parts"."part_id" IN (24, 12, 3, 26)
答案 2 :(得分:0)
再看一遍,我不确定为什么要将计数添加到连接表中。
@items = Item.includes(:parts)
@items.each do |item|
parts_count_per_item = item.parts.size
end
或
@parts = Part.includes(:items)
@parts.each do |part|
items_count_per_part = part.items.size
end