78

我是一名 PHP 开发人员,正在学习 Ruby on Rails 的强大功能,我喜欢 ActiveRecord,我注意到一些非常有趣的东西,这就是 ActiveRecord 方法如何检测方法链的末尾以执行查询。

@person = Person.where(name: 'Jason').where(age: 26)

# In my humble imagination I'd think that each where() executes a database query
# But in reality, it doesn't until the last method in the chain

这个法术是如何运作的?

4

4 回答 4

166

where方法返回一个ActiveRecord::Relation对象,并且该对象本身不会发出数据库查询。重要的你使用这个对象的地方。

在控制台中,您可能正在这样做:

@person = Person.where(name: "Jason")

然后blammo它发出一个数据库查询并返回似乎是一个名为 Jason 的每个人的数组。耶,活动记录!

但是你做这样的事情:

@person = Person.where(name: "Jason").where(age: 26)

然后发出另一个查询,但这个查询是针对 26 岁的叫 Jason 的人。但它只发出一个查询,那么另一个查询去哪儿了?


正如其他人所建议的那样,发生这种情况是因为该where方法返回了一个代理对象。它实际上并不执行查询并返回数据集,除非它被要求这样做。

当您在控制台中运行任何内容时,它将输出您运行的任何结果的检查版本。如果您1输入控制台并按回车键,您将1返回,因为1.inspectis 1。魔法!也一样"1"。许多其他对象没有inspect定义方法,因此 Ruby 回退到Object返回可怕的东西的对象<Object#23adbf42560>

每个ActiveRecord::Relation对象都inspect定义了方法,因此它会引发查询。当您在控制台中编写查询时,IRB 将调用inspect该查询的返回值并输出几乎人类可读的内容,例如您看到的数组。


inspect如果您只是在标准 Ruby 脚本中发出此命令,则在检查(通过)对象或通过 using 迭代eachto_a调用该方法之前不会执行任何查询。

在这三件事中的一件发生之前,您可以在其上链接任意数量的where语句,然后当您调用inspectto_a或者each在其上,它最终将执行该查询。

于 2012-05-25T02:21:25.127 回答
8

有许多被称为“踢球者”的方法实际上会触发对数据库的查询。在此之前,他们只是创建 AST 节点,一旦启动,就会生成实际的 SQL(或编译成的语言)并运行查询。

有关如何完成此操作的更深入解释,请参阅此博客文章

于 2012-05-25T00:49:54.707 回答
4

您可以阅读代码,但这里的一个概念是代理模式。

@person 可能不是真正的对象,而是该对象的代理,当您需要一些属性时,活动记录最终会执行查询。Hibernate 也有同样的概念。

于 2012-05-25T00:48:41.377 回答
-2

也许为时已晚,但您可以使用哈希:

@person = Person.where({name: "Jason", age: 26})

结果查询:

SELECT "person".* FROM "person"  WHERE "person"."name" = 'Jason' AND "person"."age" = 26
于 2017-11-28T15:39:26.723 回答