Каково влияние использования AsEnumerable() на пейджинг?
Я понимаю, что если у вас есть какая-то функция в запросе linq, которая не отображается на SQL-запрос, то сначала вы должны вызвать.AsEnumerable():
var model = _service.GetQuery
.Where(data => data.SomeFlag == true)
.Select(data => new { Foo = CalculateFoo(data.Bar); });
Не может быть выполнено с помощью linq to sql, но добавив AsEnumerable (), мы можем заставить предложение.Select() выполнять linq для объектов:
var model = _service.GetQuery
.Where(data => data.SomeFlag == true)
.AsEnumerable()
.Select(data => new { Foo = CalculateFoo(data.Bar); });
Но что, если набор данных очень большой - как AsEnumerable влияет на подкачку страниц? Если я говорю:
var page = model.Skip((page > 0 ? page - 1 : 0) * rows).Take(rows);
Поскольку модель теперь IEnumerable вместо IQueryable, когда мы говорим model.Skip().Take(), нужно ли сначала загружать весь набор данных из базы данных, прежде чем он сможет пропустить и взять? (Это победит цель пейджинга)
РЕДАКТИРОВАТЬ: Вопрос был написан в общих чертах - это конкретные детали:
Я не контролирую пейджинг. Я генерирую модель и передаю ее компоненту сетки (в данном случае DevExpress, но может быть любой сеткой). Это компонент сетки, который выдает команды пейджинга. Любое решение, которое предполагает использование.Skip (). Take () перед AsEnumerable (), здесь невозможно.
Поэтому мне нужно иметь возможность передать эту модель в сетку, а также убедиться, что модель использует отложенное выполнение:
var model = _service.GetQuery
.Where(data => data.SomeFlag == true)
.Select(data => new {
data.Id,
data.Customer.Code,
data.Customer.Name,
// etc, select a few other properties
Foo = CalculateFoo(data.Bar);
});
Так что теперь у меня есть проблема рок-н-ролла:
- Если я передам эту модель в сетку, она выдаст исключение при отображении текущей страницы, потому что linq to sql не может выполнить CalculateFoo()
- Если я добавлю AsEnumerable (), то сетка может показать текущую страницу, но для этого она должна загрузить весь набор данных (загрузка многих тысяч строк только для отображения 200 из них)
- Если я оставлю столбец Foo вне модели, то мы снова отложим выполнение, но в сетке отсутствует столбец.
2 ответа
Если вы делаете пейджинг, вам нужна... страница и итого
так
var query= _service.GetQuery
.Where(data => data.SomeFlag == true);
ViewBag.Total = query.Count();
var model = query.Skip((page > 0 ? page - 1 : 0) * rows).Take(rows)
.AsEnumerable()
.Select(data => new { Foo = CalculateFoo(data.Bar); });
Поскольку модель теперь IEnumerable вместо IQueryable, когда мы говорим model.Skip().Take(), нужно ли сначала загружать весь набор данных из базы данных, прежде чем он сможет пропустить и взять? (Это победит цель пейджинга)
Это факт: перед пейджингом у вас всегда должен быть только ваш запрос "принят пользователем linq2entites".
РЕДАКТИРОВАТЬ
Я не контролирую пейджинг. Я генерирую модель и передаю ее компоненту сетки (в данном случае DevExpress, но может быть любой сеткой). Это компонент сетки, который выдает команды пейджинга. Любое решение, которое предполагает использование.Skip (). Take () перед AsEnumerable(), здесь невозможно.
Ну, "обычно" грид-системы разрешают (telerik) (или имеют только (MvcContrib) настраиваемую подкачку страниц (что означает, что вы должны предоставить результаты "выбранной страницы" + общее количество, как в моем ответе).
Я выполнил поиск (вы могли бы пойти дальше) по "Пользовательская страница подкачки DevExpress", которая дает мало результатов. Не знаю, если они вам интересны.
Примеры ответа
Просто позвони Skip/Take
до AsEnumerable()
:
var model = _service.GetQuery
.Where(data => data.SomeFlag == true)
.Skip((page > 0 ? page - 1 : 0) * rows).Take(rows)
.AsEnumerable()
.Select(data => new { Foo = CalculateFoo(data.Bar); });