Результаты запроса не могут быть перечислены более одного раза? - PullRequest
14 голосов
/ 01 сентября 2009

Я использую LINQ to SQL для получения результата поиска хранимой процедуры FullTextSearch в Sql server 2008. Я перетащил процедуру из проводника сервера в конструктор и получил метод, созданный с соответствующим типом и параметрами возврата. Теперь проблема в том, что мне нужно получить Count результата вызова этого метода, поэтому, используя мой метод репозитория (который вызовет метод Sproc и вернет результат как IQueryable), я сделаю следующий вызов.

var result = repository.FullTextSearch(searchText);
        int resultsCount = result.Count();
        var ret = result.Skip((pageNumber - 1) * PageSize).Take(PageSize).ToList();

Этот код генерирует исключение InvalidOperationException каждый раз, когда я пытаюсь запустить его, исключение говорит (да, вы догадались!) «Результаты запроса не могут быть перечислены более одного раза».

Метод, сгенерированный для Sproc, возвращает ISingleResult, который должен быть O.K. НАСКОЛЬКО МНЕ ИЗВЕСТНО. Мне нужно поддерживать постраничное отображение своего представления, поэтому мне нужно знать общее количество страниц, что (опять же AFAIK) возможно только в том случае, если я смогу получить количество всех элементов.

Что мне здесь не хватает, ребята?

Ответы [ 4 ]

17 голосов
/ 01 сентября 2009

Что вы можете сделать, это добавить ToList() вызов после repository.FullTextSearch(searchText). Таким образом, результаты извлекаются с сервера, после чего вы можете делать с ними все, что захотите (поскольку они теперь загружаются в память).

Теперь вы пытаетесь выполнить один и тот же SQL-запрос дважды, что довольно неэффективно.

14 голосов
/ 01 сентября 2009

Поскольку это выполнение хранимой процедуры, все ваши прекрасные Skip / Take в значительной степени избыточны в любом случае ... у нее нет другого выбора, кроме как вернуть все данные обратно (вызовы хранимых процедур не могут быть скомпонованы). Единственное, что он может сделать, это не материализовать объекты для некоторых из них.

Интересно, лучше ли было бы реорганизовать код, чтобы сделать два вызова:

int result = repository.FullTextSearchCount(searchText);
var result = repository.FullTextSearch(searchText, skip, take); // or similar

т.е. сделать параметры подкачки частью SPROC (и для фильтрации в базе данных, используя ROW_NUMBER() / OVER(...), или переменные таблиц, временные таблицы и т. д.), или, альтернативно, что-то похожее с параметром OUTPUT в sproc:

int? count = null;
var result = repository.FullTextSearch(searchText, skip, take, ref count);

(мне кажется, что OUTPUT становится ref, поскольку TSQL OUTPUT действительно является вводом-выводом)

5 голосов
/ 03 ноября 2011

Использование ToList() может помочь избежать этой проблемы.

var result = repository.FullTextSearch(searchText).ToList();
1 голос
/ 01 сентября 2009

Я бы посоветовал, если вам нужен подсчет, сначала выполните результат. а затем запустите счетчик из самого списка, поскольку вы не используете resultsCount при выполнении результатов.

var result = repository.FullTextSearch(searchText);
var ret = result.Skip((pageNumber - 1) * PageSize).Take(PageSize).ToList();
int resultsCount = ret.Count();
...