ActiveRecord查询链

时间:2011-08-30 18:08:38

标签: ruby-on-rails ruby activerecord rails-activerecord active-record-query

这个ruby / rails构造总是困惑我:

User.where(:name => "Thiago").limit(3).using(:slave_one)

这必须从左到右执行,以便每次连续调用都有一个接收器。所以我们从User类开始,在其上调用where,返回ActiveRecord::Relation的实例。然后在该实例上调用limit,返回另一个ActiveRecord::Relation实例。然后在该实例上调用using(恰好选择一个分片)。我想,整个事情在ActiveRecord::Relation对象内建立了一个SQL查询。我的问题是,“是什么触发了查询的实际执行”?它不能在链中的任何特定点执行,因为链中可能存在进一步修改查询的后继者。即使在using返回之后,查询仍然无法执行,因为它无法知道是否将其他方法添加到链中。显然,它在构建之后会执行查询,那么查询实际上是如何调用的?


谢谢......我现在看到链中方法的名称有“语义”。有些人会进一步修改正在构建的查询。最后一个也可能是最后一个可能是需要提取数据的类型。

2 个答案:

答案 0 :(得分:7)

在您询问某些数据之前,ActiveRecord :: Relation不会打扰与数据库交谈。例如:

User.where(:name => "Thiago").limit(3).using(:slave_one).count
# talks to the database here ----------------------------^^^^^

如果你看一下ActiveRecord :: Relation,你会看到它包含ActiveRecord::QueryMethods,其中的大部分内容都是这样的:

def x(*args)
  relation = clone
  # merge args into relation
  relation
end

所以Relation只是逐个构建一个查询,直到你做了一些需要执行查询的事情;然后它将构建适当的SQL,将其发送到数据库,并对数据库发回的内容做一些有用的(理论上)。

另请注意,每个QueryMethods方法都会返回克隆和修改的关系,因此您可以执行以下操作:

r1 = User.where(:name => 'Pancakes')
r2 = r1.limit(3)

然后使用r1抓取所有匹配或r2以抓取其中的三个。

答案 1 :(得分:3)

这个构造(在你构建它时查询永远不会执行)是故意的。它叫做Lazy Loading。

当您第一次向关系询问数据时,查询会执行。 IE如果你有:

@users = User.where(:name => "Thiago").limit(3).using(:slave_one)
@users.first.name #the query executes here

通常这是在视图模板中第一行调用查询数据时执行的。