Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DotNetCore Entity Framework | Generic Pagination

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.

like image 575
L.querter Avatar asked Oct 29 '22 03:10

L.querter


1 Answers

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 !

like image 91
L.querter Avatar answered Nov 09 '22 08:11

L.querter