Как получить общее количество результатов до .Take(), но при использовании .Take()

Я использую .Take() для получения фиксированного количества результатов.

Как лучше всего получить TotalCountBeforeTake (т.е. как будто я не использовал .Take())?

Могу ли я получить TotalCountBeforeTake, не выполняя запрос дважды?

        var Results = (from results in db.FindWords(term)
                       orderby results.word
                       select results.word).Take(100);

        //just to get the total record count
        int TotalCountBeforeTake = (from results in db.FindWords(term)
                            select results.word).Count();

        // only showing 100 out of TotalCountBeforeTake results,
        // but in order to know the TotalCountBeforeTake I had to run the query twice.
        foreach (var result in Results)
        {
            Console.Write(result.ToString());
        }

person inspite    schedule 24.08.2013    source источник
comment
Лучший способ сделать это действительно зависит от рассматриваемого IEnumerable. При поддержке базы данных выполнение нескольких запросов будет быстрее. Если бы это был Linq to Objects, то написание цикла while, вероятно, было бы быстрее.   -  person Billy ONeal    schedule 24.08.2013
comment
О, я приму это к сведению, это db drivem   -  person inspite    schedule 24.08.2013
comment
Говоря о IEnumerable<T>, убедитесь, что то, что вы получаете от db.FindWords(term), является IQueryable<T>.   -  person ta.speot.is    schedule 24.08.2013


Ответы (3)


Вы хотите запросить две вещи — общее количество элементов и подмножество элементов. Итак, вам нужно запустить два запроса:

    // Define queries
    var query1 = from results in db.FindWords(term)
                 orderby results.word
                 select results.word;

    var query2 = query1.Take(100);

    // Run queries
    int totalCountBeforeTake = query1.Count();

    foreach (var result in query2)
    {
        Console.Write(result.ToString());
    }
person dtb    schedule 24.08.2013
comment
О, я думал, что попробовал это, и это не сработало, я, должно быть, сделал глупую ошибку, когда пытался! Спасибо. - person inspite; 24.08.2013
comment
Этот ответ действительно оптимизирован. Рассмотрим таблицу базы данных из одного миллиона слов. Это сначала COUNT(*) их, а затем SELECT TOP 100 ... их. Значительно быстрее, чем чтение миллиона слов и сохранение их в списке. - person ta.speot.is; 24.08.2013

Я не знаю, как подсчитать, не разбивая это (надеюсь, кто-то другой знает), но в вашей ситуации я бы предложил:

//first get the records
var query = (from results in db.FindWords(term)
                       orderby results.word
                       select results.word).ToList();

//get the total record count
int TotalCountBeforeTake = query.Count();

// only showing 100 out of results,
foreach (var result in query.Take(100))
{
    Console.Write(result.ToString());
}
person Paul D'Ambra    schedule 24.08.2013
comment
Это то, что я подумал, может быть лучшим решением, то есть получить один раз, но перечислить дважды. Мне было интересно посмотреть, есть ли у кого-нибудь что-нибудь лучше. Спасибо - person inspite; 24.08.2013
comment
Обратите внимание, что если общее количество элементов велико, этот подход будет очень медленным по сравнению с выполнением двух запросов, поскольку он должен полностью загрузить каждый элемент в память. - person dtb; 24.08.2013
comment
@dtb Я почти предложил по существу те же запросы, что и ваши ... как всегда с такими вещами, относительная стоимость запроса по сравнению с перечислением - это то, что нужно сбалансировать ... если этот db.FindWords (термин) является текстовым поиском против таблицы без полнотекстового индекса у вас может быть очень дорогой запрос по сравнению с дешевым перечислением. Потыкай палкой и посмотри, что будет :-) - person Paul D'Ambra; 24.08.2013

IEnumerables и LINQ используются для создания цепочки выбора. Прежде чем вы действительно начнете итерацию, ничего не выполняется (кроме создания цепочки выбора).

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

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

Другими словами: преобразуйте выражение linq в массив и продолжайте.

 var Results = (from results in db.FindWords(term)
                     orderby results.word
                     select results.word).Take(100).ToArray();

Теперь можно считать, перебирать без потери производительности.

person alzaimar    schedule 24.08.2013
comment
Это не дает подсчета до того, как вы наберете 100, если только это не работает иначе, чем я думаю. - person Paul D'Ambra; 24.08.2013
comment
Нет, это не работает. Подсчет массива каждый раз будет показывать только 100 или меньше, а не общее количество элементов, которое вернул бы запрос. - person Billy ONeal; 24.08.2013