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

 更新时间:2022-01-19 14:00:04   作者:佚名   我要评论(0)

目录需求目标原理与思路实现定义分页结果数据结构添加对于分页结果的Mapping Profile创建分页查询请求创建查询Controller验证总结需求
查询中

需求

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

目标

实现分页查询返回。

原理与思路

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

除了最基本的实现方式之外,我们可能还需要实现关于分页数据结构的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应用之实现查询分页的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
  • .NET 6开发TodoList应用之实现ActionFilter
  • .NET 6开发TodoList应用之实现接口请求验证
  • .NET?6开发TodoList应用之实现DELETE请求与HTTP请求幂等性
  • .NET 6开发TodoList应用之实现PUT请求
  • .NET 6开发TodoList应用之实现全局异常处理
  • .NET 6开发TodoList应用之使用AutoMapper实现GET请求
  • .NET?6开发TodoList应用之实现Repository模式
  • .NET?6开发TodoList应用之使用MediatR实现POST请求
  • .NET 6开发TodoList应用引入数据存储
  • .NET?6开发TodoList应用引入第三方日志库
  • .NET 6开发TodoList应用实现结构搭建
  • .NET?6开发TodoList应用实现系列背景
  • 使用.NET?6开发TodoList应用之引入数据存储的思路详解
  • 使用.NET?6开发TodoList应用之领域实体创建原理和思路
  • .NET?6开发TodoList应用之请求日志组件HttpLogging介绍

相关文章

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

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

    目录需求目标原理与思路实现定义分页结果数据结构添加对于分页结果的Mapping Profile创建分页查询请求创建查询Controller验证总结需求 查询中
    2022-01-19
  • .Net?Core微服务网关Ocelot集成Consul

    .Net?Core微服务网关Ocelot集成Consul

    有consul基础的都知道,consul可以发现新增的服务,剔除掉无效的服务,赋予应用自动伸缩的能力。而ocelot如果集成了consul,那ocelot也能拥有
    2022-01-19
  • Go中defer使用场景及注意事项

    Go中defer使用场景及注意事项

    目录1. 简介1.1 使用场景1.2 注意事项2. defer 数据结构3. 执行机制3.1 栈上分配3.2 开放编码4. 参考1. 简介 defer 会在当前函数返回前执行传
    2022-01-19
  • python从入门到实践之字典

    python从入门到实践之字典

    目录字典概述字典定义查找字典的值给字典增加键值对给字典修改键值对的值给字典删除键值对字典中可以包含列表值列表中可以包含字典字典中可以
    2022-01-19
  • 正则表达式用法详解

    正则表达式用法详解

    正则表达式之基本概念 在我们写页面时,往往需要对表单的数据比如账号、身份证号等进行验证,而最有效的、用的最多的便是使用正则表达式来验
    2022-01-09
  • PHP随机生成用户信息实例分析

    PHP随机生成用户信息实例分析

    本文给大家介绍如何随机生成用户信息(号码、名字、时间),希望对需要的朋友有所帮助! 随机生成号码 function generate_name($count,$ty
    2022-01-08
  • php封装pdo实例以及pdo长连接的优缺点总结

    php封装pdo实例以及pdo长连接的优缺点总结

    一、前言 最近需要写脚本来实现崩溃日志的入库,不出所料又是脱离于框架的,那么行吧,咱们只能自己封装数据库相关操作了。博主这里选择了封
    2022-01-08
  • php中echo、print和print_r的区别点及用法总结

    php中echo、print和print_r的区别点及用法总结

    本教程操作环境:windows10系统、PHP7.1版,DELL G3电脑 php中echo、print和print_r的区别是什么 echo是PHP语句, print和print_r是函数,语句
    2022-01-08
  • PHP对接抖音开发平台接口的详细教程

    PHP对接抖音开发平台接口的详细教程

    目录一、说明二、代码三、代码运行需知 四、功能扩展五、接口调用需要注意的点六、接口文档中的 ‘坑'(以订单列表接口为例)1、请求参数、响
    2022-01-08
  • php7 安装mysqli实例讲解

    php7 安装mysqli实例讲解

    本文操作环境:Windows7系统、php-7.1.5、Dell G3。 php7 怎么安装mysqli&#63; centos php7 安装mysqli扩展心得 在新配服务器时发现,php无法
    2022-01-08

最新评论