I was looking for a way to do generic pagination with Entity Framework in Dotnet Core 1.1.
I found this guide on MSDN: https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/sorting-filtering-and-paging-with-the-entity-framework-in-an-asp-net-mvc-application
But this was not generic and did not allow me to reuse code.
Included is the answer I used if anyone is looking into this, I thought it would be nice to share.
It uses custom Attributes on models, and returns a pagination model.
EDIT:
The answer below is not correct due to the orderBy not translating into L2E correctly. All the records will be retrieved and sorted in memory what results into poor performance. Check comments for more information and posisble solution.
ORIGNAL:
My solution:
Model.cs:
public class User
{
// Sorting is not allowed on Id
public string Id { get; set; }
[Sortable(OrderBy = "FirstName")]
public string FirstName { get; set; }
}
SortableAttribute.cs:
public class SortableAttribute : Attribute
{
public string OrderBy { get; set; }
}
PaginationService.cs:
public static class PaginationService
{
public static async Task<Pagination<T>> GetPagination<T>(IQueryable<T> query, int page, string orderBy, bool orderByDesc, int pageSize) where T : class
{
Pagination<T> pagination = new Pagination<T>
{
TotalItems = query.Count(),
PageSize = pageSize,
CurrentPage = page,
OrderBy = orderBy,
OrderByDesc = orderByDesc
};
int skip = (page - 1) * pageSize;
var props = typeof(T).GetProperties();
var orderByProperty = props.FirstOrDefault(n => n.GetCustomAttribute<SortableAttribute>()?.OrderBy == orderBy);
if (orderByProperty == null)
{
throw new Exception($"Field: '{orderBy}' is not sortable");
}
if (orderByDesc)
{
pagination.Result = await query
.OrderByDescending(x => orderByProperty.GetValue(x))
.Skip(skip)
.Take(pageSize)
.ToListAsync();
return pagination;
}
pagination.Result = await query
.OrderBy(x => orderByProperty.GetValue(x))
.Skip(skip)
.Take(pageSize)
.ToListAsync();
return pagination;
}
}
Pagination.cs (model):
public class Pagination<T>
{
public int CurrentPage { get; set; }
public int PageSize { get; set; }
public int TotalPages { get; set; }
public int TotalItems { get; set; }
public string OrderBy { get; set; }
public bool OrderByDesc { get; set; }
public List<T> Result { get; set; }
}
UserController.cs (inside controller), context is EntityFramework context:
[HttpGet]
public async Task<IActionResult> GetUsers([FromQuery] string orderBy, [FromQuery] bool orderByDesc, [FromQuery] int page, [FromQuery] int size)
{
var query = _context.User.AsQueryable();
try
{
var list = await PaginationService.GetPagination(query, page, orderBy, orderByDesc, size);
return new JsonResult(list);
}
catch (Exception e)
{
return new BadRequestObjectResult(e.Message);
}
}
I hope this helps someone in the future !
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With