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

发布于 2024-11-16 18:39:03 字数 608 浏览 3 评论 0原文

我想知道是否有一种方法可以通过 ActiveRecord 从数据库中获取对象,而无需 Rails 构建整个对象(仅几个字段)。

例如, 我有时需要检查某个对象是否包含某个字段。 假设我有一个 Student 对象引用 Bag 对象(每个学生都有一个书包)。 我需要检查是否存在一个女学生,她的包里有超过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 不要构建对象,或者只构建某个字段(也在关联中)?

I'm wondering if there's a way to fetch objects from the DB via ActiveRecord, without having Rails build the whole objects (just a few fields).

For example,
I sometimes need to check whether a certain object contains a certain field.
Let's say I have a Student object referencing a Bag object (each student has one bag).
I need to check if a female student exists that her bag has more than 4 pencils.

In ActiveRecord, I would have to do something like this:

exists = Student.female.find(:all, conditions => 'bags.pencil_count > 4', :include => :bag).size > 0

The problem is that if there are a 1000 students complying with this condition,
a 1000 objects would be built by AR including their 1000 bags.

This reduces me to using plain SQL for this query (for performance reasons), which breaks the AR.
I won't be using the named scopes, and I would have to remember to update them all around the code,
if something in the named scope changes.

This is an example, but there are many more cases that for performance reasons,
I would have to use SQL instead of letting AR build many objects,
and this breaks encapsulation.

Is there any way to tell AR not to build the objects, or just build a certain field (also in associations)?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

泛滥成性 2024-11-23 18:39:03

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

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

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

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

If you're only testing for the existence of a matching record, just use Model.count from ActiveRecord::Calculations, e.g.:

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

count simply (as the name of the class implies), does the calculation and doesn't build any objects.

(And for future reference it's good to know the difference between :include and :joins. The former eager-loads the associated model, whereas the latter does not, but still lets you use those fields in your :conditions.)

辞别 2024-11-23 18:39:03

Jordan 在这里给出了最好的答案 - 特别是回复:使用 join 而不是 include (因为 join 实际上不会创建 bag 对象),

我只是补充说,如果您实际上仍然需要“学生”对象(只是上面有少量信息)您还可以使用 :select 关键字 - 它的工作方式就像在 mysql 中一样,意味着数据库 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进行转换例如)

Jordan gave the best answer here - especially re: using joins instead of include (because join won't actually create the bag objects)

I'll just add to it by saying that if you do actually still need the "Student" objects (just with the small amount of info on it) you can also use the :select keyword - which works just like in mysql and means the db I/O will be reduced to just the info you put in the select - and you can also add derived fields form the other tables eg:

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

would give eg:

Jenny has 5 pencils in her bag
Samantha has 14 pencils in her bag
Jill has 8 pencils in her bag

(though note that a derived field (eg pencil_count) will be a string - you may need to cast eg with student.pencil_count.to_i )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文