Rails ActiveRecord如何在没有多个查询的情况下链接“ where”子句?


75

我是一名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

此法术如何运作?


最后一种方法没有做到这一点。它没有办法知道。考虑x = Person.where(..); @person = x.where(..),其性能应相同。稍后它会执行,那么触发了什么?;-)

Answers:


157

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

在控制台中,您可能正在执行以下操作:

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

然后,blammo发出数据库查询,并返回似乎每个由Jason组成的数组。是的,活动记录!

但是随后您将执行以下操作:

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

然后发出另一个查询,但这是给26岁的叫Jason的人的。但这只是发出一个查询,那么另一个查询又去了哪里呢?


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

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

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


如果您只是在标准Ruby脚本中发布此代码,则只有在检查了该对象(通过inspect)或使用对其进行了迭代eachto_a调用了方法之后,才会执行查询。

直到发生这三件事之一,您都可以where在其上链接任意数量的语句,然后在调用或对其进行调用时inspect,它最终将执行该查询。to_aeach


1
相关的Railscast用Rails源代码对其进行了解释。
flexus

8

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

请参阅此博客文章,以获取有关如何完成此操作的更深入的说明。


4

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

@person可能不是真正的对象,而是该对象的代理,并且当您需要某个属性时,活动记录将最终执行查询。Hibernate具有相同的概念。


-2

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

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

结果查询:

SELECT "person".* FROM "person"  WHERE "person"."name" = 'Jason' AND "person"."age" = 26

2
person = Person.where({name:“ Jason”,age:26})和person = Person.where(name:“ Jason”,age:26)完全相同-Ruby将第二个参数转换为哈希自动
Ghoti
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.