我想知道是否有办法通过ActiveRecord从数据库中获取对象,而不需要Rails构建整个对象(只有几个字段)。
例如, 我有时需要检查某个对象是否包含某个字段。 假设我有一个引用Bag对象的Student对象(每个学生都有一个包)。 我需要检查一名女学生是否存在她的行李超过4支铅笔。
在ActiveRecord中,我必须做这样的事情:
exists = Student.female.find(:all, conditions => 'bags.pencil_count > 4', :include => :bag).size > 0
问题是,如果有1000名学生符合这一条件, AR将建造1000个物品,包括1000个袋子。
这减少了我使用普通SQL进行此查询(出于性能原因),这会破坏AR。 我不会使用命名范围,我必须记住在代码周围更新它们, 如果指定范围内的某些内容发生变化。
这是一个例子,但出于性能原因,还有更多案例, 我将不得不使用SQL而不是让AR构建许多对象, 这打破了封装。
有没有办法告诉AR不要构建对象,或只是构建某个字段(也在关联中)?
答案 0 :(得分:4)
如果您只测试是否存在匹配记录,请使用ActiveRecord::Calculations中的Model.count
,例如:
exists = Student.female.count( :conditions => 'bags.pencil_count > 4',
:joins => :bag
) > 0
count
简单地(如类所暗示的那样),进行计算并且不构建任何对象。
(并且为了将来参考,了解:include
和:joins
之间的区别是很好的。前者急切加载相关模型,而后者不加载,但仍允许您使用这些字段你的:conditions
。)
答案 1 :(得分:2)
乔丹在这里给出了最好的答案 - 尤其是:使用连接而不是包含(因为连接实际上不会创建包对象)
我只是添加它说,如果你确实仍然需要“学生”对象(只需要少量的信息),你也可以使用:select关键字 - 这就像在mysql中一样并且意味着db I / O将简化为您在select中放置的信息 - 您还可以从其他表中添加派生字段,例如:
students = Student.female.all(
:select => 'students.id, students.name, bags.pencil_count AS pencil_count',
:conditions => 'students.gender = 'F' AND bags.pencil_count > 4',
:joins => :bag
)
students.each do |student|
p "#{student.name} has #{student.pencil_count} pencils in her bag"
end
会给出例如:
Jenny has 5 pencils in her bag
Samantha has 14 pencils in her bag
Jill has 8 pencils in her bag
(虽然请注意派生字段(例如pencil_count)将是一个字符串 - 您可能需要使用student.pencil_count.to_i进行强制转换)