2

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

4

2 回答 2

4

如果您只是测试是否存在匹配记录,只需使用Model.countfrom ActiveRecord::Calculations,例如:

exists = Student.female.count(  :conditions => 'bags.pencil_count > 4',
                                :joins => :bag
                             ) > 0

count简单地说(正如类名所暗示的那样),进行计算并且不构建任何对象。

:include(并且为了将来参考,最好了解和之间的区别:joins。前者急切加载关联的模型,而后者没有,但仍然允许您在 . 中使用这些字段:conditions。)

于 2011-06-21T07:44:35.837 回答
2

乔丹在这里给出了最好的答案 - 特别是:使用连接而不是包含(因为连接实际上不会创建袋子对象)

我只是补充说,如果您确实仍然需要“学生”对象(只是上面有少量信息),您还可以使用 :select 关键字 - 它就像在 mysql 中一样工作,意味着db I/O 将简化为您在选择中输入的信息 - 您还可以从其他表中添加派生字段,例如:

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 进行转换)

于 2011-06-21T08:25:42.880 回答