2012-08-25 3 views
2

Предположим, мы имеем следующий LINQ запрос:Когда запрос LINQ действительно выполняется?

var query = 
    from c in Customers 
    where c.Country == "Italy" 
    orderby c.Name 
    select new { c.Name, c.City }; 

Компилятор преобразует это так:

IEnumerable<Customer> query = 
     Customers 
     .Where(c => c.Country == "Italy"); 
     .OrderBy(c => c.Name) 
     .Select(c => new { c.Name, c.City }); 

Тогда я coud использовать запрос следующим образом:

foreach (var name_city_pair in query) ... 

Вопросы являются:

  • Похоже, данные, указанные в запросе , уже запрошены , когда я использую цикл foreach. Итак, когда происходит это действие запроса? Это когда я определяю объект запроса LINQ IEnumerable<Customer> ?

  • Если номер данных слишком большой, есть ли какой-либо поздний запрос механизм? (Я не уверен, что правильное слово, чтобы описать это, но я надеюсь, что вы меня.)

+0

Я думаю, что у вас может быть несколько синтаксических ошибок выше. Вы выбираете анонимный тип, а затем указываете, что выбранный объект имеет тип Customer, а затем итерации по запросу, как IEnumerable . – vossad01

+0

Спасибо за ваше напоминание. Исправлено сейчас. – smwikipedia

ответ

5

LINQ использует отложенное выполнение, где это возможно. В вашем примере запрос выполняется только при повторении результатов.

Методы, которые начинаются с To (например, ToList), вызывают немедленное выполнение запроса. Также некоторые методы, которые возвращают одно значение, такое как Count, вызывают немедленное выполнение запроса.

1

Запрос не выполняется перед foreach. Каждая итерация в вашем цикле foreach вернет один результат из вашего запроса.

Никогда не существует полностью материализованного набора данных, поэтому он также не может быть слишком большим.

Запрос LINQ отменяет выполнение. По мере того, как вы итерации, он будет «скользить» вперед по вашим данным, применяя предикаты и прогнозы, которые вы указали.

3

Вообще говоря, LINQ стремится быть максимально ленивым. Например, вы бы ожидать, чтобы это выглядело примерно так негласно:

foreach (string name in query) ... 
//Roughly translates into 
while (query.MoveNext()) 
{ 
    string name = query.Current; 
    ... 
} 

Что только получает результаты, как это нуждается в них, один за другим. Это «ленивое»/«потоковое» мышление работает через весь запрос - выбирает вызовы OrderBy по мере необходимости, который вызывает «Где по мере необходимости», который вызывает коллекцию по мере необходимости.

Единственная странность - это «OrderBy», которая по соображениям реализации может получить все необходимые результаты перед их упорядочиванием, а затем передать результат. Это извлечение произойдет, когда оно будет вызвано первым.

+0

Это предполагает Linq-To-Objects? И если да, будет ли ваш ответ другим, если бы это был Linq-To-Sql или Entity Framework? –

+0

Специфика предполагает LinqToObjects, хотя все реализации должны стараться быть ленивыми IIRC.MongoDB, например, будет компилировать и отправлять запрос в БД при первом вызове и возвращать «MongoCursor», который будет обрабатывать получение документа для каждой итерации IIRC. [Может обрабатывать документы 4 МБ времени IIRC]. – NPSF3000

Смежные вопросы