Lepszy sposób na odpytywanie strony danych i uzyskanie całkowitej liczby w ramach entity Framework 4.1?

Obecnie, gdy muszę uruchomić zapytanie, które będzie używane w / paging robię to coś takiego:

//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();

To działa, ale zastanawiałem się, czy jest możliwe, aby poprawić to, aby być bardziej wydajnym, nadal używając linq? Nie mogłem wymyślić sposobu, aby połączyć liczbę z pobieraniem danych w jednej podróży do DB bez użycia zapisanego proc.

Author: C.J., 2011-10-14

3 answers

Poniższe zapytanie otrzyma liczbę i wyniki stron w jednej podróży do bazy danych, ale jeśli sprawdzisz SQL w LINQPad, zobaczysz, że nie jest zbyt ładny. Mogę sobie tylko wyobrazić, jak to będzie wyglądać dla bardziej złożonego zapytania.

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);

Dla prostego zapytania Jak to, prawdopodobnie można użyć jednej metody (2 wycieczki do bazy danych, lub za pomocą GroupBy, aby zrobić to w 1 podróży) i nie zauważyć dużej różnicy. Myślę, że w przypadku skomplikowanych procedur, najlepszym rozwiązaniem byłaby procedura składowana.

 71
Author: Jeff Ogata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-10-14 17:26:31

Sugeruję wykonanie dwóch zapytań dla pierwszej strony, jednego dla całkowitej liczby i jednego dla pierwszej strony lub wyników.

Buforuj całkowitą liczbę do użycia podczas przechodzenia poza pierwszą stronę.

 3
Author: Bryan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-10 20:34:46

Odpowiedź Jeffa Ogaty może być trochę zoptymalizowana.

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();

To robi prawie to samo, tylko że nie będzie przeszkadzać bazie danych z niepotrzebną grupą by. Jeśli nie jesteś pewien, czy Twoje zapytanie będzie zawierać co najmniej jeden wynik i nie chcesz, aby kiedykolwiek wyrzuciło wyjątek, możesz uzyskać totalCount w następujący (aczkolwiek mniej czystszy) sposób:

var totalCount = results.FirstOrDefault()?.TotalCount ?? 0;
 2
Author: Rudey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-26 15:57:55