Вопрос по ruby-on-rails – Как Rails ActiveRecord объединяет предложения «где» без нескольких запросов?

61

Я - разработчик 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(..), который должен работать одинаково. Это происходит через некоторое время, так что же является триггером? ;-) user166390

Ваш Ответ

4   ответа
138

where метод возвращаетActiveRecord::Relation объект, и сам по себе этот объект не выдает запрос к базе данных. Это & APOS; swhere Вы используете этот объект, который имеет значение.

В консоли вы, вероятно, делаете это:

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

А потомblammo он выдает запрос к базе данных и возвращает массив всех по имени Jason. Yay, Active Record!

Но тогда вы делаете что-то вроде этого:

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

И затем это выдает другой запрос, но этот для людей, которых называют Джейсон, которым 26 лет. Но это только выдачаone запрос, так где же другой запрос?


Как полагают другие, это происходит потому, чтоwhere Метод возвращает объект прокси. Он на самом деле не выполняет запрос и не возвращает набор данных, если его не просят сделать это.

Когда ты бежишьanything в консоли он будет выводить проверенную версию результата того, что вы запустили. Если вы положите1 в консоли и нажмите Enter, вы получите1 назад, потому что1.inspect является1, Магия! То же самое касается"1", Множество других объектов не имеютinspect определенный метод, и поэтому Руби возвращается к тому, наObject который возвращает что-тоghastly лайк<Object#23adbf42560>.

КаждыйActiveRecord::Relation объект имеетinspect метод, определенный на нем, так что он вызывает запрос. Когда вы пишете запрос в вашей консоли, IRB будет вызыватьinspect на возвращаемом значении из этого запроса и выведите что-то, почти читаемое человеком, например, массив, который вы увидите.


Если бы вы просто выдавали это в стандартном скрипте Ruby, то ни один запрос не был бы выполнен, пока объект не был осмотрен (черезinspect) или был повторен с помощьюeachили имелto_a метод вызван на это.

До тех пор, пока не произойдет одно из этих трех событий, вы можетеwhere заявления на это, как вам нравится, а затем, когда выdo вызовinspect, to_a или жеeach на этом, тогда он, наконец, выполнит этот запрос.

Error: User Rate Limit Exceeded
Error: User Rate Limit ExceededRailscastError: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
-3

Возможно, слишком поздно, но вы можете использовать хеш:

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

Результирующий запрос:

SELECT "person".* FROM "person"  WHERE "person"."name" = 'Jason' AND "person"."age" = 26
Error: User Rate Limit Exceeded
4

Вы можете прочитать код, но одна концепция здесь - шаблон прокси.

Вероятно, @person - не реальный объект, а прокси для этого объекта, и когда вам нужен какой-то атрибут, активная запись наконец выполняет запрос. Hibernate имеет ту же концепцию.

7

Существует ряд методов, которые известны как «кикеры». который фактически запускает запрос к базе данных. До этого они просто создают узлы AST, которые после запуска генерируют фактический SQL (или язык, на котором выполняется компиляция) и запускают запрос.

Увидетьэтот блог для более глубокого объяснения того, как это делается.

Похожие вопросы