我基本没有Rails的经验,但我正在尝试帮助一个正在学习编程的朋友。虽然我有很多SQL的经验,但我仍然很难通过联接来实现对简单查询的正确操作。
我有两个表,drawings
和drawing_types
。drawings
有一个外键指向drawing_types
,它有一个type_description
列。这显然是你能想象到的最基本的关系。在SQL中,我会使用以下代码来获取所有带有正确type_descriptions
的图纸:
SELECT d.*, dt.type_description FROM drawings as d
INNER JOIN drawing_types as dt ON dt.id = d.drawing_type_id;
这是一个高效的SQL查询,可以准确地返回我想要的内容:绘图列表以及它们的文本类型描述。
但是,我无论如何都无法让Rails生成并使用这样一个单一的查询。我最多只能做到两个查询,这显然表明它在代码中执行“join”,而不是让数据库来执行。有时候它还会执行N+1个查询!?
以下是模型的代码:
class Drawing < ActiveRecord::Base
attr_accessible :image, :drawing_type_id
belongs_to :drawing_type
end
class DrawingType < ActiveRecord::Base
attr_accessible :type_description
has_many :drawings
end
这里是相关的控制器代码:
@drawings = Drawing.includes(:drawing_type)
这里是视图:
<% @drawings.each do |drawing| %>
<tr>
<td><b><%= drawing.drawing_type.type_description %></b></td>
这将生成两个SQL查询,一个查询
drawings.*
,另一个查询所有描述,然后在代码中明确查找这些描述。如果我将includes
更改为joins
,它将执行1+M+N个SQL查询(其中M表示图纸类型数量,N表示图纸数量)!?!?!我可以通过使用以下内容将正确的SQL连接记录到日志中来解决此问题(取自此处):
@drawings = Drawing.select("drawings.*, drawing_types.type_description").
joins("INNER JOIN drawing_types ON drawing_types.id = drawings.drawing_type_id")
但是,Rails似乎只把结果作为一组绘图的数组使用,忽略结果中的
type_description
列,因此它会执行额外的M+N查询!所有这些变化都“可行”,因为对于所有这些变化,页面都会正确呈现,但是相对于应该执行的单个正确SQL连接来说,它们都是错误的。
由于这是在一个非常无聊的网站模式中可能找到的最基本的关系之一,因此必须有一种简单的方法来正确地完成此操作,但是我已经四处寻找过了,包括阅读了这里的许多答案和所有文档,但无法弄清楚如何做到这一点。
谢谢, Chris
select
中使用字符串,因为我无法弄清如何消除共享列名(例如:id)的歧义,所以我做了.select(["drawings.*", :type_description])
。此外,值得强调的是,此解决方案直接将属性放在返回的对象上,因此您可以通过drawing.type_description
访问它,在正常的includes
语法中,您需要使用drawing.drawing_type.type_description
。 - Chris Hecker