【问题标题】:Why does a query in rails with a limit not work unless .all is put on the end为什么除非 .all 放在末尾,否则在有限制的 Rails 中查询不起作用
【发布时间】:2011-10-04 13:07:53
【问题描述】:

我有一个这样的查询:

locations = Location.order('id ASC').limit(10)

它返回一个包含 500 条左右记录的数组 - 表中的所有记录 - 即忽略限制子句。

如果我把 .all 放在最后:

locations = Location.order('id ASC').limit(10).all

它工作并返回 10 条记录。

这段代码在 rake 任务中运行,如果有什么不同,我正在使用 PostgreSQL。

为什么要这样做?当然 .all 不应该是必需的。我错过了什么?

【问题讨论】:

  • 我想知道它是否与延迟加载有关:除非附加 .all, .first ... 否则不会触发查询
  • 您使用的是哪个版本的 Rails?因为我使用的是 3.0.9,我无法重现这个..
  • 你运行的是什么版本的 Rails?它适用于我在 Rails 3.0x 中。您是否尝试将“.to_sql”附加到末尾以查看它正在运行什么查询?
  • 将 to_sql 添加到第一个示例会产生正确的 SQL:SELECT "locations".* FROM "locations" ORDER BY id ASC LIMIT 10 但第二个失败,因为 .all 进入数组

标签: ruby-on-rails activerecord rake


【解决方案1】:

我认为行为取决于您在设置 locations 变量后如何处理它。这是因为Location.order('id ASC').limit(10) 不是在查询记录,而是返回一个ActiveRecord::Relation 类型的对象。只有在您对该对象调用 allfirsteachmap 等时,才会发生查询。

在我的测试中,

Location.order('id ASC').limit(10).map { |l| l.id }

如您所料,返回一个包含 10 个 id 的数组。但是

Location.order('id ASC').limit(10).count

返回数据库中的位置总数,因为它执行 SQL

SELECT COUNT(*) FROM "locations" LIMIT 10

返回位置行的完整计数(限制是返回的行数,而不是计数本身)。

因此,如果您通过迭代将Location.order('id ASC').limit(10) 的结果视为一个数组,您应该得到与添加all 相同的结果。如果你打电话给count,你不会。有点不幸,因为我认为理想情况下它们的行为应该相同,并且您不必知道您正在处理的是 ActiveRecord::Relation 而不是数组。

【讨论】:

  • 好的,我想你已经搞定了。我正在使用 puts "#{locations.size} items to look up" 检查位置的大小,忘记了位置在那时是一个关系而不是一个数组。所以 .size 似乎在 Relation 和由对该 Relation 的查询产生的数组上有不同的行为,这当然没有帮助。
【解决方案2】:

好的,这是我的解释 首先,如果您执行Location.order('id ASC').limit(10).class,您将在site with rails API 上看到ActiveRecord::Relation 下一个ActiveRecord::Relation 没有方法all 但它包含ActiveRecord::FinderMethods,如果您看那里,您会找到下一个

# File activerecord/lib/active_record/relation/finder_methods.rb, line 142
def all(*args)
  args.any? ? apply_finder_options(args.first).to_a : to_a
end

所以它调用to_a 方法 正如railscasts 中提到的,此方法定义为

def to_a  
  ...
  @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql)  
  ...  
  @records  
end 

所以它在第三行使用@records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql) 进行 SQL 查询

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 2016-11-30
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 2020-05-18
    • 2023-03-15
    相关资源
    最近更新 更多