DotNetCore实体框架 | 通用分页

5
我正在寻找一种在Dotnet Core 1.1中使用Entity Framework进行通用分页的方法。我在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,但这不是通用的,也不能让我重复使用代码。
以下是我使用的答案,如果有人正在研究此问题,我认为分享一下会很好。它使用模型上的自定义属性,并返回一个分页模型。
1个回答

3

编辑:

由于orderBy无法正确转换为L2E,下面的答案是不正确的。所有记录将在内存中检索和排序,导致性能不佳。请查看评论以获取更多信息和可能的解决方案。

原始内容:

我的解决方案:

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(模型):

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(控制器内部),上下文是EntityFramework上下文:

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

我希望这能帮助未来某个时候需要的人!

1
为什么要限制它们?那不是一个有用的事情。如果这段代码在你的环境中工作,那么你的跳过和取出操作将在整个数据集上运行。EF 不会理解你代码中的反射部分该怎么处理。除非 .Net Core 引入了一些奇怪的东西,但我对此表示怀疑。 - DavidG
1
@IvanStoev 我刚刚测试了一下,和我们预料的一样,EF Core并不能自动识别反射代码并在内存中对所有内容进行排序。 - DavidG
1
不要传递 string orderBy,直接传递表达式 (Expression<Func<T, object>> orderBy) 并执行 OrderBy(orderBy) - DavidG
1
@L.querter 当然可以 :) 例如,您可以查看我的回答如何使用字符串创建EF排序表达式?或类似的SO帖子来了解一下。 - Ivan Stoev
2
@IvanStoev和DavidG,谢谢你们:) 你们帮了我很多。 - L.querter
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接