2009-06-26 5 views
30

В Entity Framework, используя LINQ для лиц, пейджинг базы данных обычно делается следующим образом:пейджинга в Entity Framework

int totalRecords = EntityContext.Context.UserSet.Count; 
var list  = EntityContext.Context.UserSet 
       .Skip(startingRecordNumber) 
       .Take(pageSize) 
       .ToList(); 

Это приводит к TWO обращений к базе данных.

Пожалуйста, расскажите, как уменьшить его до ОДНОГО вызова базы данных.

Thank you.

+6

В EF это приводит к ошибке, вы должны позвонить OrderBy до вызова Skip :) Было бы хорошо, если вы обновите свой код. Кто-то мог потерять много времени, копируя код с поста. –

+0

Трюк, как это сделать, находится в http://stackoverflow.com/questions/7767409/better-way-to-query-a-page-of-data-and-get-total-count-in-entity-framework -4-1, но лучше иметь простой дизайн с 2 вызовами –

ответ

4

Хммм ... фактический вызов, который использует пейджинг, является вторым - это один вызов.

Второй вызов состоит в том, чтобы определить общее количество строк - это совсем другая операция, и я не знаю, каким образом вы могли бы объединить эти две отдельные операции в один вызов базы данных с помощью Entity Framework.

Вопрос: вы действительно нужно общее количество строк? Зачем? Это стоит второй вызов базы данных или нет?

Еще один вариант, который вы хотели бы использовать, - использовать EntityObjectSource (в ASP.NET), а затем привязать его, например. GridView и включить AllowPage и AllowSorting и т. д. в GridView и позволить среде выполнения ASP.NET обрабатывать всю важную работу по извлечению соответствующей страницы данных и ее отображению.

Марк

+3

Вам нужны полные записи, чтобы вы знали, сколько страниц у вас в вашем выгружаемом интерфейсе. Интересно, можете ли вы просто сделать список. – rball

+0

Ну, List.Count, вероятно, извлечет все строки из базы данных - это определенно не то, что вы хотите. Кроме того, я уверен, что Linq to Entities вернет пустой набор из вас запрашивает страницу за пределами фактического набора данных - так снова: зачем вам нужно общее количество строк? В самом деле? Уверен, что приятно показывать «Страница 5 из 17» на вашей странице - можете ли вы жить без нее? –

+0

Спасибо за ответы. Пользовательский интерфейс требует панели пейджера, поэтому требуется общее количество записей. – dev

7

Использование ESQL и отображения хранимой процедуры к объекту может решить эту проблему. SP возвращает totalRows в качестве выходного параметра и текущей страницы в качестве набора результатов.

CREATE PROCEDURE getPagedList(
@PageNumber int, 
@PageSize int, 
@totalRecordCount int OUTPUT 
AS 

//Return paged records 

Просьба сообщить.

Thank you.

+0

+1 Ницца. Это даст вам 1 вызов базы данных. Вы все равно выполняете два запроса, но они будут быстрыми и маленькими. –

33

Что случилось с двумя вызовами? Это небольшие и быстрые запросы. Базы данных предназначены для поддержки множества небольших запросов.

Разработка комплексного решения для выполнения одного запроса для поискового вызова не приведет к большой окупаемости.

3
ALTER proc [dbo].[GetNames] 
    @lastRow bigint, 
    @pageSize bigint, 
    @totalRowCount bigint output 
as 
begin 

select @totalRowCount = count(*) from _firstNames, _lastNames 

select 
    FirstName, 
    LastName, 
    RowNumber 
from 
(
    select 
     fn.[FirstName] as FirstName, 
     ln.[Name] as LastName, 
     row_number() over(order by FirstName) as RowNumber 
    from 
     _firstNames fn, _lastNames ln 
) as data 
where 
    RowNumber between (@lastRow + 1) and (@lastRow + @pageSize) 

end 

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

+4

Это действительно возможно. См. Этот ответ: http://stackoverflow.com/a/7771298/1131804 –

-1

Предположим, что вы хотите получить подробную информацию о Page 2 с размер_страницы = 4

int page =2; 
int pagesize=4; 

var pagedDetails= Categories.Skip(pagesize*(page-1)).Take(pagesize) 
.Join(Categories.Select(item=>new {item.CategoryID,Total = Categories.Count()}),x=>x.CategoryID,y=>y.CategoryID,(x,y)=>new {Category = x,TotalRows=y.Total}); 

Выход будет иметь все детали категории и TotalRows.

One DB call.

генерируемый SQL

-- Region Parameters 
DECLARE @p0 Int = 2 
DECLARE @p1 Int = 4 
-- EndRegion 
SELECT [t2].[CategoryID], [t2].[CategoryName], [t2].[Description], [t2].[Picture], [t5].[value] AS [TotalRows] 
FROM (
    SELECT [t1].[CategoryID], [t1].[CategoryName], [t1].[Description], [t1].[Picture], [t1].[ROW_NUMBER] 
    FROM (
     SELECT ROW_NUMBER() OVER (ORDER BY [t0].[CategoryID], [t0].[CategoryName]) AS [ROW_NUMBER], [t0].[CategoryID], [t0].[CategoryName], [t0].[Description], [t0].[Picture] 
     FROM [Categories] AS [t0] 
     ) AS [t1] 
    WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1 
    ) AS [t2] 
INNER JOIN (
    SELECT [t3].[CategoryID], (
     SELECT COUNT(*) 
     FROM [Categories] AS [t4] 
     ) AS [value] 
    FROM [Categories] AS [t3] 
    ) AS [t5] ON [t2].[CategoryID] = [t5].[CategoryID] 
ORDER BY [t2].[ROW_NUMBER] 
+0

Неверно. Он всегда учитывает все категории. Даже если приложение применяется к основному запросу. Более того, он не возвращает объекты категории, но анонимный тип, и он подсчитывает снова и снова для каждой категории. –

+0

Требование: 1- Получить информацию о странице со страницей 2- Убедитесь, что вы вернули всю информацию в одном БД-ЗВОНОК. Надеюсь, вы понимаете, о чем говорите ... Вы видели требования выше? Вы пробовали решение, предоставленное мной, или вы делитесь своими мыслями, просто глядя? Если вы попробуете, это будет один вызов БД ... попробуйте, а затем прокомментируйте. Конечно, субъект категории не имеет общего свойства счета, но мы все еще хотим его обратно в том же вызове ... Тип возврата - анонимный класс с конкретными свойствами Категория и итоговые числа. – Satchi

+0

One * маленький * вопрос. Что делать, если они хотят 'Categories.Where (c => c.Name.Contains (" a "))'? –

0

Эти запросы слишком малы для DBManager, и я не могу понять, почему вы хотите это сделать, во всяком случае для уменьшения его ОДНОГО использования вызовов базы данных это:

var list  = EntityContext.Context.UserSet 
       .Skip(startingRecordNumber) 
       .Take(pageSize) 
       .ToList(); 
int totalRecords = list.Count; 
Смежные вопросы