ActiveRecord Query Chains - PullRequest
       10

ActiveRecord Query Chains

3 голосов
/ 30 августа 2011

Эта конструкция из рубинов и рельсов всегда озадачивает меня:

User.where(:name => "Thiago").limit(3).using(:slave_one)

Это должно выполняться слева направо, чтобы у каждого последующего вызова был получатель. Итак, мы начинаем с класса User, вызываем where для него, который возвращает экземпляр ActiveRecord::Relation. Затем limit вызывается для этого экземпляра, возвращая другой экземпляр ActiveRecord::Relation. Затем using вызывается для этого экземпляра (который выбирает осколок). Я полагаю, что все это создает запрос SQL внутри объекта ActiveRecord::Relation. Мой вопрос: «что вызывает фактическое выполнение запроса»? Он не может выполняться в какой-либо конкретной точке цепочки, поскольку в цепочке могут быть преемники, которые дополнительно изменяют запрос. Даже после возврата using запрос все равно не может быть выполнен, потому что он не может знать, привязаны ли дополнительные цепочки к цепочке. Очевидно, что он выполняет запрос после его создания, так как на самом деле этот запрос вызывается?


Спасибо ... Теперь я вижу, что имена методов в цепочке имеют "семантику". Некоторые из них будут дополнительно изменять создаваемый запрос Последний и единственный последний может быть того типа, который требует выборки данных.

Ответы [ 2 ]

7 голосов
/ 30 августа 2011

ActiveRecord :: Relation не утруждает себя связью с базой данных, пока вы не запросите у нее некоторые данные. Например:

User.where(:name => "Thiago").limit(3).using(:slave_one).count
# talks to the database here ----------------------------^^^^^

Если вы посмотрите на ActiveRecord :: Relation, вы увидите, что он включает в себя ActiveRecord :: QueryMethods и большинство из них выглядит следующим образом:

def x(*args)
  relation = clone
  # merge args into relation
  relation
end

Таким образом, Relation просто строит запрос по частям, пока вы не сделаете что-то, требующее выполнения запроса; затем он создаст соответствующий SQL, отправит его в базу данных и сделает что-то полезное (теоретически) с тем, что база данных отправит обратно.

Также обратите внимание, что каждый из методов QueryMethods возвращает клонированное и измененное отношение, поэтому вы можете делать такие вещи:

r1 = User.where(:name => 'Pancakes')
r2 = r1.limit(3)

, а затем используйте r1, чтобы захватить все спички, или r2, чтобы просто взять три из них.

3 голосов
/ 30 августа 2011

Эта конструкция (где запрос никогда не выполняется так, как вы его строите) является намеренной.Это называется Ленивая загрузка.

Запрос выполняется в первый раз, когда вы запрашиваете отношение для данных из него.IE, если у вас было:

@users = User.where(:name => "Thiago").limit(3).using(:slave_one)
@users.first.name #the query executes here

Обычно это выполняется, когда первая строка в вашем шаблоне представления запрашивает данные из запроса.

...