【发布时间】:2015-11-25 13:29:46
【问题描述】:
环境:Rails 4.2.4,Postgres 9.4.1.0
是否保证ActiveRecord#first 方法将始终返回具有最小 ID 和 ActiveRecord#last - 具有最大 ID 的记录?
我可以从 Rails 控制台看到,对于这两种方法,将适当的 ORDER ASC/DESC 添加到生成的 SQL 中。但是另一个 SO 线程 Rails with Postgres data is returned out of order 的作者告诉 first 方法返回 NOT 第一条记录...
ActiveRecord 优先:
2.2.3 :001 > Account.first
帐户负载 (1.3ms) SELECT "accounts".* FROM "accounts" ORDER BY "accounts"."id" ASC LIMIT 1
ActiveRecord 上次:
2.2.3 :002 > Account.last
帐户负载 (0.8ms) SELECT "accounts".* FROM "accounts" ORDER BY "accounts"."id" DESC LIMIT 1
===========
稍后添加:
所以,我做了自己的调查(基于D 方面 的答案),答案是NO。一般来说,唯一的保证是 first 方法将从集合中返回 first 记录。它可能会作为一个副作用将ORDER BY PRIMARY_KEY 条件添加到 SQL,但这取决于记录是否已加载到缓存/内存中。
以下是从 Rails 4.2.4 中提取的方法: /activerecord/lib/active_record/relation/finder_methods.rb
# Find the first record (or first N records if a parameter is supplied).
# If no order is defined it will order by primary key.
# ---> NO, IT IS NOT. <--- This comment is WRONG.
def first(limit = nil)
if limit
find_nth_with_limit(offset_index, limit)
else
find_nth(0, offset_index) # <---- When we get there - `find_nth_with_limit` method will be triggered (and will add `ORDER BY`) only when its `loaded?` is false
end
end
def find_nth(index, offset)
if loaded?
@records[index] # <--- Here's the `problem` where record is just returned by index, no `ORDER BY` is applied to SQL
else
offset += index
@offsets[offset] ||= find_nth_with_limit(offset, 1).first
end
end
这里有几个例子要清楚:
Account.first # True, records are ordered by ID
a = Account.where('free_days > 1') # False, No ordering
a.first # False, no ordering, record simply returned by @records[index]
Account.where('free_days > 1').first # True, Ordered by ID
a = Account.all # False, No ordering
a.first # False, no ordering, record simply returned by @records[index]
Account.all.first # True, Ordered by ID
现在有多个关系的例子:
Account has_many AccountStatuses, AccountStatus belongs_to Account
a = Account.first
a.account_statuses # No ordering
a.account_statuses.first
# Here is a tricky part: sometimes it returns @record[index] entry, sometimes it may add ORDER BY ID (if records were not loaded before)
这是我的结论:
将方法 first 视为从已加载的集合中返回 first 记录(可以按 any 顺序加载,即无序)。如果我想确保 first 方法将返回具有最小 ID 的记录 - 那么我应用 first 方法的集合应该在之前适当地排序。
关于first 方法的Rails 文档是错误的,需要重写。
http://guides.rubyonrails.org/active_record_querying.html
1.1.3先
第一种方法查找按主键排序的第一条记录。
【问题讨论】:
标签: postgresql ruby-on-rails-4 activerecord