2009-06-26 16 views
30

In Entity Framework, LINQ to Entities verwenden, Datenbank Paging in der Regel in folgenden Weise durchgeführt wird:Paging in Entity Framework

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

Dies führt zu ZWEI Datenbank Anrufen.

Bitte sagen Sie, wie Sie es auf ONE-Datenbankaufruf reduzieren können.

Vielen Dank.

+6

In EF ergibt sich ein Fehler, Sie müssen OrderBy aufrufen, bevor Sie Skip aufrufen :) Wäre gut, wenn Sie Ihren Code aktualisieren. Jemand hätte viel Zeit verlieren können, um den Code aus dem Post zu kopieren. –

+0

Der Trick, wie man es macht, ist in http://stackoverflow.com/questions/7767409/better-way-to-query-a-page-of-data-and-get-total-count-in-entity-framework -4-1, aber es ist besser, ein einfaches Design mit 2 Aufrufen zu haben –

Antwort

4

Hmmm ... der eigentliche Anruf, der Paging verwendet, ist der zweite - das ist ein einziger Anruf. Der zweite Aufruf dient zur Ermittlung der Gesamtzahl der Zeilen - das ist eine ganz andere Operation, und mir ist nicht bewusst, wie Sie diese beiden unterschiedlichen Vorgänge zu einem einzigen Datenbankaufruf mit dem Entity Framework kombinieren könnten.

Frage ist: Haben Sie wirklich brauchen die Gesamtzahl der Zeilen? Wozu? Ist das einen zweiten Datenbankanruf wert oder nicht?

Eine weitere Option, die Sie hätten, wäre, die EntityObjectSource (in ASP.NET) zu verwenden und dann diese an z. eine GridView, und aktivieren Sie AllowPaging und AllowSorting usw. auf der GridView, und lassen Sie die ASP.NET-Laufzeit alle wichtigen Aufgaben der Abrufen der entsprechenden Datenseite und deren Anzeige behandeln.

Marc

+3

Sie benötigen die Gesamtzahl Datensätze, so dass Sie wissen, wie viele Seiten Sie in Ihrer ausgelagerten Schnittstelle haben. Ich frage mich, ob du nur eine Liste machen kannst. Count oder sowas? – rball

+0

Nun, der List.Count würde wahrscheinlich alle Zeilen aus der Datenbank holen - das ist definitiv nicht etwas, das Sie wollen. Außerdem bin ich mir ziemlich sicher, dass Linq to Entities eine leere Menge von Ihnen zurückgibt, die nach einer Seite fragt, die über die eigentliche Datenmenge hinausgeht - also noch einmal: Warum brauchen Sie die Gesamtzahl der Zeilen? "Ja wirklich?" Sicher ist es schön, "Seite 5 von 17" auf deiner Seite zu zeigen - kannst du ohne es leben? –

+0

Danke für die Antworten. UI benötigt eine Pager-Leiste, so dass die Gesamtzahl der Datensätze benötigt wird. – dev

7

Mit ESQL- und Zuordnen eines gespeicherten Prozedur zu einer Einheit kann das Problem lösen. SP gibt totalRows als Ausgabeparameter und aktuelle Seite als Ergebnismenge zurück.

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

//Return paged records 

Bitte beraten.

Vielen Dank.

+0

+1 Schön. Das würde Ihnen 1 Datenbankaufruf geben. Sie würden immer noch zwei Abfragen ausführen, aber sie werden schnell und klein sein. –

33

Was ist falsch bei zwei Anrufen? Sie sind kleine und schnelle Abfragen. Datenbanken sind so konzipiert, dass sie viele kleine Abfragen unterstützen.

Die Entwicklung einer komplexen Lösung für eine Abfrage für Paging wird Sie nicht viel auszahlen lassen.

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 

Es gibt keine Möglichkeit, dies in einen Anruf zu bekommen, aber das funktioniert schnell genug.

+4

Es ist tatsächlich möglich. Siehe diese Antwort für wie: http://stackoverflow.com/a/7771298/1131804 –

-1

Angenommen, Sie haben bekommen die Details Page 2 mit einer Seitengröße = 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}); 

Die Ausgabe alle Details der Kategorie und totalRows.

Ein DB-Aufruf.

generiert 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

Falsch. Es zählt immer alle Kategorien. Auch wenn ein Wo auf die Hauptabfrage angewendet wird. Darüber hinaus gibt es keine Kategorienentitäten zurück, sondern einen anonymen Typ, und es zählt immer wieder für jede Kategorie. –

+0

Die Voraussetzung ist: 1- Holen Sie sich die Details einer Seite mit einer Seitengröße 2- Stellen Sie sicher, dass Sie alle Informationen in einem DB CALL zurück erhalten. Ich hoffe, Sie verstehen, was Sie sprechen ... Haben Sie die oben genannten Anforderungen gesehen? Haben Sie die von mir angebotene Lösung ausprobiert oder teilen Sie Ihre Gedanken einfach mit? Wenn Sie es versuchen, wird es ein DB-Anruf sein ... bitte versuchen Sie und dann kommentieren. Natürlich hat die Kategorieentität keine total count -Eigenschaft, aber wir wollen sie immer noch in demselben Aufruf ... Der Rückgabetyp ist eine anonyme Klasse mit konkreten Eigenschaften Kategorie und TotalRows. – Satchi

+0

Eine * kleine * Frage. Was, wenn sie 'Categories.Where (c => c.Name.Contains (" a "))' möchten? –

0

Diese Anfragen sind zu klein für DBManager und ich kann nicht verstehen, warum Sie dies tun wollen, jedenfalls für sie dieser Aufforderung Verwendung einer Datenbank zu reduzieren:

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