Ruby-on-rails Rails ActiveRecord 如何在没有多个查询的情况下链接“where”子句?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10747106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How does Rails ActiveRecord chain "where" clauses without multiple queries?
提问by Ryan
I'm a PHP developer learning the awesomness of Ruby on Rails, I'm loving ActiveRecord and i noticed something really interesting, Which is how ActiveRecord methods detect the end of method chain to execute the query.
我是一名 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
How does this sorcery work?
这个法术是如何运作的?
回答by Ryan Bigg
The wheremethod returns an ActiveRecord::Relationobject, and by itself this object does not issue a database query. It's whereyou use this object that matters.
该where方法返回一个ActiveRecord::Relation对象,该对象本身不发出数据库查询。重要的是你在哪里使用这个对象。
In the console, you're probably doing this:
在控制台中,您可能会这样做:
@person = Person.where(name: "Jason")
And then blammoit issues a database query and returns what appears to be an array of everyone named Jason. Yay, Active Record!
然后blammo它发出一个数据库查询并返回一个似乎是一个名为 Jason 的每个人的数组。是的,活动记录!
But then you do something like this:
但是你会做这样的事情:
@person = Person.where(name: "Jason").where(age: 26)
And then that issues another query, but this one's for people who are called Jason who are 26. But it's only issuing onequery, so where'd the other query go?
然后它会发出另一个查询,但这个查询是针对 26 岁的名为 Jason 的人的。但它只发出一个查询,那么另一个查询去哪里了?
As others have suggested, this is happening because the wheremethod returns a proxy object. It doesn't actually perform a query and return a dataset unless it's asked to do that.
正如其他人所建议的,这是因为该where方法返回一个代理对象。它实际上并不执行查询并返回数据集,除非它被要求这样做。
When you run anythingin the console, it's going to output the inspected version of the outcome of whatever it is you ran. If you put 1in the console and hit enter, you'll get 1back because 1.inspectis 1. Magic! Same goes for "1". A variety of other objects don't have an inspectmethod defined and so Ruby falls back to the one on Objectwhich returns something ghastlylike <Object#23adbf42560>.
当你在控制台中运行任何东西时,它会输出你运行的任何结果的检查版本。如果您1输入控制台并按回车键,您将1返回,因为1.inspectis 1。魔法!也一样"1"。其他各种对象不具有inspect定义的方法,并因此Ruby回落到上一个Object返回的东西可怕的喜欢<Object#23adbf42560>。
Every single ActiveRecord::Relationobject has the inspectmethod defined on it so that it causes a query. When you write the query in your console, IRB will call inspecton the return value from that query and output something almost human readable, like the Array that you'd see.
每个ActiveRecord::Relation对象都inspect定义了方法,因此它会引发查询。当您在控制台中编写查询时,IRB 将调用inspect该查询的返回值并输出一些几乎人类可读的内容,例如您将看到的 Array。
If you were just issuing this in a standard Ruby script, then no query would be executed until the object was inspected (via inspect) or was iterated through using each, or had the to_amethod called on it.
如果您只是在标准 Ruby 脚本中发出此命令,那么在检查对象(通过inspect)或通过 using 迭代each或在其上to_a调用方法之前,不会执行任何查询。
Up until one of those three things happen, you can chain as many wherestatements on it as you will like and then when you docall inspect, to_aor eachon it, then it will finally execute that query.
直到这三种情况之一发生,你可以链尽可能多的where就可以了报表,你会喜欢的,然后当你做的呼叫inspect,to_a或each在其上,那么它最终将执行该查询。
回答by x1a4
There are a number of methods that are known as "kickers" that actually fire off the query to the database. Prior to that, they just create AST nodes, which once kicked, will generate the actual SQL (or language being compiled to) and run the query.
有许多被称为“kickers”的方法实际上将查询发送到数据库。在此之前,他们只是创建 AST 节点,一旦被踢,将生成实际的 SQL(或正在编译的语言)并运行查询。
See this blog postfor a deeper explanation of how this is done.
有关如何完成此操作的更深入解释,请参阅此博客文章。
回答by Tiago Peczenyj
You can read the code, but one concept here is the proxy pattern.
您可以阅读代码,但这里的一个概念是代理模式。
Probably @person is not the real object but a proxy to this object and when you need some attribute there the active record finally execute the query. Hibernate has the same concept.
可能@person 不是真正的对象,而是该对象的代理,当您需要某些属性时,活动记录最终会执行查询。Hibernate 也有同样的概念。
回答by Robert Cvjetkovi?
Maybe bit too late but you can use a hash:
也许为时已晚,但您可以使用哈希:
@person = Person.where({name: "Jason", age: 26})
Resulting query:
结果查询:
SELECT "person".* FROM "person" WHERE "person"."name" = 'Jason' AND "person"."age" = 26

