Un modo migliore per interrogare una pagina di dati e ottenere il conteggio totale nel framework di quadro 4.1?

Attualmente quando ho bisogno di eseguire una query che verrà utilizzata w / paging faccio qualcosa di simile a questo:

//Setup query (Typically much more complex) var q = ctx.People.Where(p=>p.Name.StartsWith("A")); //Get total result count prior to sorting int total = q.Count(); //Apply sort to query q = q.OrderBy(p => p.Name); q.Select(p => new PersonResult { Name = p.Name }.Skip(skipRows).Take(pageSize).ToArray(); 

Funziona, ma mi chiedevo se è ansible migliorarlo per essere più efficiente mentre si usa ancora linq? Non riuscivo a pensare a un modo per combinare il conteggio w / il recupero dei dati in un singolo viaggio al DB senza utilizzare un proc memorizzato.

La seguente query otterrà il conteggio e i risultati della pagina in un unico viaggio nel database, ma se si controlla l’SQL in LINQPad, vedrete che non è molto carina. Posso solo immaginare come sarebbe una query più complessa.

 var query = ctx.People.Where (p => p.Name.StartsWith("A")); var page = query.OrderBy (p => p.Name) .Select (p => new PersonResult { Name = p.Name } ) .Skip(skipRows).Take(pageSize) .GroupBy (p => new { Total = query.Count() }) .First(); int total = page.Key.Total; var people = page.Select(p => p); 

Per una semplice query come questa, potresti probabilmente utilizzare uno dei due metodi (2 viaggi nel database o utilizzare GroupBy per farlo in 1 viaggio) e non notare molta differenza. Per qualcosa di complesso, penso che una procedura memorizzata sarebbe la soluzione migliore.

Suggerisco di fare due query per la prima pagina, una per il conteggio totale e una per la prima pagina o i risultati.

Memorizza il conteggio totale da utilizzare mentre ti sposti oltre la prima pagina.

La risposta di Jeff Ogata può essere ottimizzata un po ‘.

 var results = query.OrderBy(p => p.Name) .Select(p => new { Person = new PersonResult { Name = p.Name }, TotalCount = query.Count() }) .Skip(skipRows).Take(pageSize) .ToArray(); // query is executed once, here var totalCount = results.First().TotalCount; var people = results.Select(r => r.Person).ToArray(); 

Questo fa più o meno la stessa cosa, tranne che non disturberà il database con un GROUP BY non necessario. Quando non sei sicuro che la tua query conterrà almeno un risultato e non vorrà mai lanciare un’eccezione, puoi ottenere totalCount nel modo seguente (anche se meno pulito):

 var totalCount = results.FirstOrDefault()?.TotalCount ?? 0;