Chr*_*ini 4 postgresql activerecord ruby-on-rails ruby-on-rails-3
我有2条记录Foo
,id为1和2.两者都是按顺序创建的.请记住,在Postgres中,记录没有固有的顺序.
在Rails控制台中.Foo.first
并Foo.last
返回最后一条记录.我的印象是Foo.first
会返回第一张唱片.
这是捕获.SQL查询看起来像:
SELECT "foos".* FROM "foos" LIMIT 1
SELECT "foos".* FROM "foos" ORDER BY "foos"."id" DESC LIMIT 1
Run Code Online (Sandbox Code Playgroud)
第二个查询(Foo.last
)有一个ORDER BY DESC
.那么为什么AR没有ORDER BY ASC
for .first
?这背后的逻辑是什么?似乎有点"不一致".
我可以通过以下方式轻松解决此问题:Foo.order('id ASC').first
相反.但寻找解释.
它没有任何逻辑,如果对first
(或last
那个问题)有任何意义,那么如果你忽略了将显式顺序指定first
为当前范围链的参数或作为当前范围链的一部分,它将引发异常.除非指定了明确的顺序,否则在关系数据库的上下文中都first
没有last
任何意义.
我的猜测是,如果没有明确的话,谁写的first
假设order by whatever_the_pk_is
是隐含的order by
.然后他们可能做了一些实验来经验验证他们的假设,它恰好按照他们所期望的特定表格和数据库进行工作(迷你咆哮:这就是为什么你永远不会假设未指明的行为;如果某个特定的行为是没有明确指定,即使当前实现的行为方式或者经验证据表明它的行为方式,也不要假设它.
如果你追踪一个简单的M.first
,你会发现它这样做:
limit(1).to_a[0]
Run Code Online (Sandbox Code Playgroud)
没有明确的排序,所以你得到数据库感觉使用的随机排序,可能是order by pk
或者它可能是磁盘上的表的块顺序.如果你追踪M.last
,你会得到find_last
:
def find_last
#...
reverse_order.limit(1).to_a[0]
#...
end
Run Code Online (Sandbox Code Playgroud)
def reverse_order
relation = clone
relation.reverse_order_value = !relation.reverse_order_value
relation
end
Run Code Online (Sandbox Code Playgroud)
该@reverse_order_value
实例变量没有被初始化,因此会一开始就是nil
和!
将它变成一个true
.如果你四处寻找如何@reverse_order_value
使用,你会得到reverse_sql_order
:
def reverse_sql_order(order_query)
order_query = ["#{quoted_table_name}.#{quoted_primary_key} ASC"] if order_query.empty?
#...
Run Code Online (Sandbox Code Playgroud)
还有作者关于订购的无效假设让所有人都知道.该行应该是:
raise 'Specify an order you foolish person!' if order_query.empty?
Run Code Online (Sandbox Code Playgroud)
我建议你总是使用.order(...).limit(1).first
而不是first
或者last
说一切都很好而且明确; 当然,如果你想要改变last
这种.order
状况.或者你总是可以说.first(:order => :whatever)
并且.last(:order => :whatever)
再次使一切都明确.
归档时间: |
|
查看次数: |
977 次 |
最近记录: |