2010-05-18 4 views

ответ

6

Вы можете сделать оба.

IEnumerable<T> query = ...complicated query; 
int c = query.Count(); 
query = query.Take(n); 

Просто выполните счет перед взятием. это вызовет выполнение запроса дважды, но я считаю, что это неизбежно.

Если это в контексте Linq2SQL, как следует из вашего комментария, это будет фактически запрашивать базу данных дважды. Что касается ленивой загрузки, хотя это будет зависеть от того, как фактически используется результат запроса.

Например: если у вас есть две таблицы говорят Product и ProductVersion где каждый Product имеет несколько ProductVersions ассоциированных с помощью внешнего ключа.

если это ваш запрос:

var query = db.Products.Where(p => complicated condition).OrderBy(p => p.Name).ThenBy(...).Select(p => p); 

где вы просто выбрать Products, но после выполнения запроса:

var results = query.ToList();//forces query execution 
results[0].ProductVersions;//<-- Lazy loading occurs 

, если ссылаться на любой внешний ключ или связанный с ним объект, который не был частью исходный запрос, тогда он будет ленивый загружен. В вашем случае счетчик не вызовет никакой ленивой загрузки, потому что он просто возвращает int. но в зависимости от того, что вы на самом деле делаете с результатом Take(), у вас может возникнуть или не возникнет ленивая загрузка. Иногда бывает сложно определить, есть ли у вас LazyLoading ocurring, чтобы проверить, что вы должны регистрировать свои запросы, используя свойство DataContext.Log.

+0

, если вы используете отложенную загрузку, она все равно выполняется дважды. Я все еще не уверен, как работает отложенная загрузка. – Kieran

+0

@ Киран, вы делаете linq2sql? или linq для объектов или что-то еще? – luke

4

Проще всего было бы просто сделать Count запроса, а затем сделать Take:

var q = ...; 
var count = q.Count(); 
var result = q.Take(...); 
2

Это можно сделать в одном запросе Linq-to-SQL (где будет выполняться только один оператор SQL). Сгенерированный SQL-код выглядит неприятным, так что ваше исполнение может отличаться.

Если это ваш запрос:

IQueryable<Person> yourQuery = People 
    .Where(x => /* complicated query .. */); 

Вы можете добавить к нему следующий:

var result = yourQuery 
    .GroupBy (x => true) // This will match all of the rows from your query .. 
    .Select (g => new { 
     // .. so 'g', the group, will then contain all of the rows from your query. 
     CountAll = g.Count(), 
     TakeFive = g.Take(5), 
     // We could also query for a max value. 
     MaxAgeFromAll = g.Max(x => x.PersonAge) 
    }) 
    .FirstOrDefault(); 

Который позволит вам получить доступ к данным, как так:

// Check that result is not null before access. 
// If there are no records to find, then 'result' will return null (because of the grouping) 
if(result != null) { 

    var count = result.CountAll; 

    var firstFiveRows = result.TakeFive; 

    var maxPersonAge = result.MaxAgeFromAll; 

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