entity framework 6 버전으로 페이징 처리를 아래와 같이 처리해 봤습니다.
public StudentsContainer GetStudents(int currentPage, int recordsPerPage, string sortKey, string sortOrder, string searchfor)
{
var pageNumber = currentPage; //현재페이지
var pageSize = recordsPerPage; //페이지 카운트
var begin = (pageNumber - 1) * pageSize; //시작 index 부분
var totalNumberOfRecords = db.Students.Count(r => searchfor == "null" || r.LastName.Contains(searchfor) || r.FirstMidName.Contains(searchfor));
List<Student> results = null;
switch (sortOrder)
{
case "ASC":
switch (sortKey)
{
case "lastName":
results = db.Students.Where(r => searchfor == "null" || r.LastName.Contains(searchfor) || r.FirstMidName.Contains(searchfor))
.OrderBy(r => r.LastName)
.Skip(begin)
.Take(pageSize).ToList();
break;
case "firstName":
results = db.Students.Where(r => searchfor == "null" || r.LastName.Contains(searchfor) || r.FirstMidName.Contains(searchfor)).OrderBy(r => r.FirstMidName).Skip(begin).Take(pageSize).ToList();
break;
}
break;
case "DESC":
switch (sortKey)
{
case "lastName":
results = db.Students.Where(r => searchfor == "null" || r.LastName.Contains(searchfor) || r.FirstMidName.Contains(searchfor)).OrderByDescending(r => r.LastName).Skip(begin).Take(pageSize).ToList();
break;
case "firstName":
results = db.Students.Where(r => searchfor == "null" || r.LastName.Contains(searchfor) || r.FirstMidName.Contains(searchfor)).OrderByDescending(r => r.FirstMidName).Skip(begin).Take(pageSize).ToList();
break;
}
break;
}
var students =
results.Select(
r =>
new Student
{
EnrollmentDate = r.EnrollmentDate,
FirstMidName = r.FirstMidName,
LastName = r.LastName,
ID = r.ID
}).ToList();
var studentsContainer = new StudentsContainer { Students = students, RecordCount = totalNumberOfRecords };
return studentsContainer;
}
아래는 위에서 구현한 entity framework 6 환경에서 실행한 자동 랜더링 ms-sql 구문입니다.
실행을 해보니 where 조건으로 특정 시작 index 에서 가져온 다음, top 쿼리로 원하는 개수만큼 리스트를 가져오도록 처리 되어 있습니다.
exec sp_executesql N'SELECT top (5)
[Project1].[ID] AS [ID],
[Project1].[LastName] AS [LastName],
[Project1].[FirstMidName] AS [FirstMidName],
[Project1].[EnrollmentDate] AS [EnrollmentDate]
FROM (
SELECT [Project1].[ID] AS [ID], [Project1].[LastName] AS [LastName], [Project1].[FirstMidName] AS [FirstMidName], [Project1].[EnrollmentDate] AS [EnrollmentDate],
row_number() OVER (ORDER BY [Project1].[LastName] ASC) AS [row_number]
FROM (
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[LastName] AS [LastName],
[Extent1].[FirstMidName] AS [FirstMidName],
[Extent1].[EnrollmentDate] AS [EnrollmentDate]
FROM [dbo].[Student] AS [Extent1]
WHERE (N''null'' = @p__linq__0) OR ([Extent1].[LastName] LIKE @p__linq__1 ESCAPE N''~'') OR ([Extent1].[FirstMidName] LIKE @p__linq__2 ESCAPE N''~'')
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 55
ORDER BY [Project1].[LastName] ASC',N'@p__linq__0 nvarchar(4000),@p__linq__1 nvarchar(4000),@p__linq__2 nvarchar(4000)',@p__linq__0=N'null',@p__linq__1=N'%null%',@p__linq__2=N'%null%'
go
저는 위 처럼 top 쿼리도 좋지만, row_number 를 이용하여 between 함수로 범위 지정해서 가져오는 것을 선호 합니다.
사실 성능을 비교하자면 top 쿼리과 별 반 차이는 없습니다. 여기 블로그를 보면 paging function 인 offset 성능이 매우 좋지 않을 것을 볼 수 있습니다.
블로그 내용이 2012 년도라 지금은 많이 개선이 되어 있지 않을까 생각됩니다.
http://www.mssqlgirl.com/paging-function-performance-in-sql-server-2012.html
이 강좌는 cte 사용하는것과 사용하지 않은 것 성능 비교이네요.
http://sqlperformance.com/2015/01/t-sql-queries/pagination-with-offset-fetch
참고로 entity framework 버전 6.1.2 이상 버전에서는 offset 페이징 함수로 구현 처리 해 준다고 합니다.
사용할 때, ms-sql 2012 부터 offset 함수를 제공하므로 꼭 확인해 보길 바랍니다.
SELECT
[TransactionID]
,[ProductID]
,[ReferenceOrderID]
,[ReferenceOrderLineID]
,[TransactionDate]
,[TransactionType]
,[Quantity]
,[ActualCost]
,[ModifiedDate]
FROM [Production].[TransactionHistoryArchive]
ORDER BY [TransactionID]
OFFSET 5001 ROWS
FETCH NEXT 100 ROWS ONLY
http://erikej.blogspot.kr/2014/12/a-breaking-change-in-entity-framework.html