Rails 2.3.8:通过ActiveRecord获取对象而不构建所有对象

时间:2011-06-21 07:26:06

标签: ruby-on-rails activerecord find building

我想知道是否有办法通过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不要构建对象,或只是构建某个字段(也在关联中)?

2 个答案:

答案 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进行强制转换)