Development Tip

엔터티 프레임 워크 4.1에서 데이터 페이지를 쿼리하고 총 개수를 얻는 더 나은 방법은 무엇입니까?

yourdevel 2021. 1. 7. 20:06
반응형

엔터티 프레임 워크 4.1에서 데이터 페이지를 쿼리하고 총 개수를 얻는 더 나은 방법은 무엇입니까?


현재 페이징과 함께 사용할 쿼리를 실행해야 할 때 다음과 같이 수행합니다.

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

이것은 작동하지만 linq를 사용하면서 더 효율적으로 개선 할 수 있는지 궁금합니다. 저장된 proc을 사용하지 않고 DB로 한 번의 여행에서 데이터 검색과 함께 카운트를 결합하는 방법을 생각할 수 없었습니다.


다음 쿼리는 데이터베이스에 대한 한 번의 여행에서 개수와 페이지 결과를 가져 오지만 LINQPad에서 SQL을 확인하면 그다지 예쁘지 않다는 것을 알 수 있습니다. 더 복잡한 쿼리의 경우 어떻게 보일지 상상할 수 있습니다.

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

이와 같은 간단한 쿼리의 경우 두 가지 방법 (데이터베이스에 두 번 이동하거나을 사용하여 한 번 GroupBy에 수행)을 사용할 수 있으며 큰 차이를 느끼지 못할 수 있습니다. 복잡한 경우에는 저장 프로 시저가 최선의 솔루션이라고 생각합니다.


Jeff Ogata의 답변은 약간 최적화 될 수 있습니다.

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

이것은 불필요한 GROUP BY로 데이터베이스를 괴롭히지 않는다는 점을 제외하면 거의 동일한 작업을 수행합니다. 쿼리에 적어도 하나의 결과가 포함되어 있는지 확실하지 않고 예외가 발생하지 않도록 totalCount하려면 다음과 같은 방법으로 얻을 수 있습니다 .

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

EF Core> = 1.1.x && <3.0.0을 사용하는 사용자를위한 중요 참고 사항 :

그 당시 나는 이것에 대한 해결책을 찾고 있었고이 페이지는 구글 용어 "EF Core Paging Total Count"에 대해 1 위였습니다.

Having checked the SQL profiler I have found EF generates a SELECT COUNT(*) for every row that is returned. I have tired every solution provided on this page.

This was tested using EF Core 2.1.4 & SQL Server 2014. In the end I had to perform them as two separate queries like so. Which, for me at least, isn't the end of the world.

var query = _db.Foo.AsQueryable(); // Add Where Filters Here.


var resultsTask = query.OrderBy(p => p.ID).Skip(request.Offset).Take(request.Limit).ToArrayAsync();
var countTask = query.CountAsync();

await Task.WhenAll(resultsTask, countTask);

return new Result()
{
    TotalCount = await countTask,
    Data = await resultsTask,
    Limit = request.Limit,
    Offset = request.Offset             
};

It looks like the EF Core team are aware of this:

https://github.com/aspnet/EntityFrameworkCore/issues/13739 https://github.com/aspnet/EntityFrameworkCore/issues/11186


I suggest making two queries for the first page, one for the total count and one for the first page or results.

Cache the total count for use as you move beyond the first page.

ReferenceURL : https://stackoverflow.com/questions/7767409/better-way-to-query-a-page-of-data-and-get-total-count-in-entity-framework-4-1

반응형