.NET 6开发TodoList应用之实现查询分页

 更新时间:2022年01月01日 08:26:34   作者:CODE4NOTHING  
这篇文章介绍了.NET 6开发TodoList应用之实现查询分页,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

需求

查询中有个非常常见的需求就是后端分页,实现的方式也不算复杂,所以我们本文仅仅演示一个后端查询分页的例子。

目标

实现分页查询返回。

原理与思路

对于分页查询而言,我们需要在请求中获取当前请求的是第几页,每页请求多少项数据。在返回值中需要告诉前端,当前这一页的所有数据项列表,总共的数据项有多少。为此我们可以定义一个包装类型,供系统中所有需要提供后端分页查询返回值使用。

除了最基本的实现方式之外,我们可能还需要实现关于分页数据结构的AutoMapper转换映射,避免手动重复实现。

实现

定义分页结果数据结构

我们在Application/Common/Models中定义一个类,表示分页结果。

PaginatedList.cs

using Microsoft.EntityFrameworkCore;

namespace TodoList.Application.Common.Models;

public class PaginatedList<T>
{
    public List<T> Items { get; }
    public int PageNumber { get; }
    public int TotalPages { get; }
    public int TotalCount { get; }

    public PaginatedList(List<T> items, int count, int pageNumber, int pageSize)
    {
        PageNumber = pageNumber;
        TotalPages = (int)Math.Ceiling(count / (double)pageSize);
        TotalCount = count;
        Items = items;
    }

    // 增加属性表示是否有前一页
    public bool HasPreviousPage => PageNumber > 1;
    // 增加属性表示是否有后一页
    public bool HasNextPage => PageNumber < TotalPages;

    // 分页结果构建辅助方法
    public static async Task<PaginatedList<T>> CreateAsync(IQueryable<T> source, int pageNumber, int pageSize)
    {
        var count = await source.CountAsync();
        // 注意我们给的请求中pageNumber是从1开始的
        var items = await source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToListAsync();

        return new PaginatedList<T>(items, count, pageNumber, pageSize);
    }
}

添加对于分页结果的Mapping Profile

Application/Common/Mappings中新增一个类用于实现关于分页结果的扩展方法:

MappingExtensions.cs

using AutoMapper;
using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
using TodoList.Application.Common.Models;

namespace TodoList.Application.Common.Mappings;

public static class MappingExtensions
{
    public static Task<PaginatedList<TDestination>> PaginatedListAsync<TDestination>(this IQueryable<TDestination> queryable, int pageNumber, int pageSize)
    {
        return PaginatedList<TDestination>.CreateAsync(queryable, pageNumber, pageSize);   
    }

    public static Task<List<TDestination>> ProjectToListAsync<TDestination>(this IQueryable queryable, IConfigurationProvider configuration)
    {
        return queryable.ProjectTo<TDestination>(configuration).ToListAsync();
    }
}

创建分页查询请求

为了演示分页查询的应用,我们新增一个允许分页查询TodoItemQuery

GetTodoItemsWithPaginationQuery.cs

using System.Linq;
using AutoMapper;
using AutoMapper.QueryableExtensions;
using MediatR;
using TodoList.Application.Common.Interfaces;
using TodoList.Application.Common.Mappings;
using TodoList.Application.Common.Models;
using TodoList.Application.TodoItems.Specs;
using TodoList.Domain.Entities;

namespace TodoList.Application.TodoItems.Queries.GetTodoItems;

public class GetTodoItemsWithPaginationQuery : IRequest<PaginatedList<TodoItemDto>>
{
    public Guid ListId { get; set; }
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 10;
}

public class GetTodoItemsWithPaginationQueryHandler : IRequestHandler<GetTodoItemsWithPaginationQuery, PaginatedList<TodoItemDto>>
{
    private readonly IRepository<TodoItem> _repository;
    private readonly IMapper _mapper;

    public GetTodoItemsWithPaginationQueryHandler(IRepository<TodoItem> repository, IMapper mapper)
    {
        _repository = repository;
        _mapper = mapper;
    }

    public async Task<PaginatedList<TodoItemDto>> Handle(GetTodoItemsWithPaginationQuery request, CancellationToken cancellationToken)
    {
        return await _repository
            .GetAsQueryable(x => x.ListId == request.ListId)
            .OrderBy(x => x.Title)
            .ProjectTo<TodoItemDto>(_mapper.ConfigurationProvider)
            .PaginatedListAsync(request.PageNumber, request.PageSize);
    }
}

创建查询Controller

TodoItemController.cs

// 对于查询来说,一般参数是来自查询字符串的,所以这里用[FromQuery]
[HttpGet]
public async Task<ApiResponse<PaginatedList<TodoItemDto>>> GetTodoItemsWithPagination([FromQuery] GetTodoItemsWithPaginationQuery query)
{
    return ApiResponse<PaginatedList<TodoItemDto>>.Success(await _mediator.Send(query));
}

验证

启动Api项目,执行创建TodoList的请求:

请求

响应

总结

对于后端排序的需求来说,实现起来并不复杂,但是在这个分页的过程中,要注意一定要以某个不会轻易变动的字段来作为排序的键,否则会在多次请求后续页的过程中出现因为字段变动导致排序结果变动进而引发分页结果的前后不一致的情况。

到此这篇关于.NET 6开发TodoList应用之实现查询分页的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • NetCore实现全局模型绑定异常信息统一处理(场景分析)

    NetCore实现全局模型绑定异常信息统一处理(场景分析)

    本文主要讲解NetCore如何使用中间件捕获模型绑定的异常信息,对NetCore实现全局模型绑定异常信息统一处理场景分析及实现代码感兴趣的朋友一起看看吧
    2021-12-12
  • .Net 调用存储过程取到return的返回值

    .Net 调用存储过程取到return的返回值

    存储过程只能返回 int 类型,如果返回一个字符串 ,将会报类型转化错误,下面以示例介绍下如何取到return的值,需要的朋友可以参考下
    2014-08-08
  • ASP.NET 导出到Excel时保留换行的代码

    ASP.NET 导出到Excel时保留换行的代码

    由于Excel毕竟不是 HTML,它有自己的样式标准,在Excel 中,实现换行的方法是
    2008-12-12
  • .NET中的HashSet及原理解析

    .NET中的HashSet及原理解析

    HashSet定义在System.Collections.Generic中,是一个不重复、无序的泛型集合,本文学习下HashSet的工作原理,对.NET中的HashSet相关知识感兴趣的朋友一起看看吧
    2022-03-03
  • .NET 缓存设计的使用说明

    .NET 缓存设计的使用说明

    缓存是提高应用程序性能的最好方法之一。运用缓存可以优化数据查询,避免不必要的网络数据回传,和避免执行不必要的完全相同的数据处理逻辑。
    2013-03-03
  • ASP.NET Cache的一些总结分享

    ASP.NET Cache的一些总结分享

    最近我们的系统面临着严峻性能瓶颈问题,这是由于访问量增加,客户端在同一时间请求增加,这迫使我们要从两个方面解决这一问题,增加硬件和提高系统的性能
    2012-08-08
  • 利用noesis.Javascript开源组件.Net中执行javascript脚本

    利用noesis.Javascript开源组件.Net中执行javascript脚本

    利用Noesis.Javascript开源组件可以做到在.net中执行js脚本,同时js脚本也能调用C#函数。这个组件的获得方式:在NuGet中输入搜索"Noesis"就能找到,我们来做个搜索功能:用户能够在textbox中输入js脚本来筛选list记录
    2013-12-12
  • 总结ASP.NET C#中经常用到的13个JS脚本代码

    总结ASP.NET C#中经常用到的13个JS脚本代码

    本文总结了ASP.NET C#在实际开发过程中13个JS脚本代码,方便大家在开发中使用,希望对大家有用。
    2016-04-04
  • asp.net(c#) RSS功能实现代码

    asp.net(c#) RSS功能实现代码

    这两天一边从网上找资料,自己再测试,终于完成本站的RSS功能了!先自我恭喜下!!  
    2008-11-11
  • .net 数据表格显示控件介绍

    .net 数据表格显示控件介绍

    这篇文章主要介绍了.net 数据表格显示控件有哪些,适用于哪些场景,需要的朋友可以参考下
    2014-06-06

最新评论