Rails的ActiveRecord链“哪里”子句没有多个查询?

我是一个学习Ruby on Rails的awseomness的PHP开发人员,我喜欢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 

这个巫术是如何工作的?

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

在控制台中,你可能是这样做的:

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

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

但是,你做这样的事情:

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

然后发出另一个查询,但是这个对于被称为Jason的人来说是26个。但是它只发出一个查询,所以另一个查询去了哪里呢?


正如其他人所说,这是因为where方法返回一个代理对象。 它实际上并不执行查询并返回数据集,除非被要求这样做。

当你在控制台上运行任何东西的时候,它会输出你运行的任何结果的检查版本。 如果你把1放在控制台中,然后回车,你会得到1因为1.inspect1 。 魔法! "1" 。 其他各种各样的objets没有定义一个inspect方法,所以Ruby会回落到Object ,它会返回一些可怕的东西,如<Object#23adbf42560>

每一个ActiveRecord::Relation对象都有一个定义的inspect方法,以便它可以引起一个查询。 当您在控制台中写入查询时,IRB将调用对该查询的返回值的inspect ,并输出几乎人类可读的内容,如您将看到的Array。


如果你只是在一个标准的Ruby脚本中发布这个脚本,那么在对象被检查(通过inspect )或迭代使用each脚本之前,不会执行任何查询,或者to_a调用to_a方法。

直到发生这三件事情中的一件,你可以链接尽可能多的语句,然后当你调用inspectto_a或者each时,它将最终执行那个查询。

有一些被称为“kickers”的方法实际上是将查询引发到数据库。 在此之前,他们只是创build一个曾经踢过的AST节点,会生成实际的SQL(或正在编译的语言)并运行查询。

看到这个博客文章的更深入的解释如何做到这一点。

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

@person可能不是真正的对象,而是这个对象的代理,当你需要一些属性时,活动logging最终执行查询。 Hibernate有相同的概念。