系列导航及源代码

需求

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

目标

实现分页查询返回。

原理与思路

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

除了最基本的实现方式之外,我们可能还需要实现关于分页数据结构的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应用(13)——实现查询分页的更多相关文章

  1. 使用.NET 6开发TodoList应用(14)——实现查询过滤

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在查询请求中,还有一类常见的场景是过滤查询,也就是有限制条件的查询,落在数据库层面就是常用的Where查询子句.实现起来也很简 ...

  2. 使用.NET 6开发TodoList应用(15)——实现查询搜索

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 本文我们继续来看查询过程中的另外一个需求:搜索.搜索的含义是目标字段的全部或者部分值匹配请求中的搜索条件,对应到数据库层面是C ...

  3. 使用.NET 6开发TodoList应用(16)——实现查询排序

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 关于查询的另一个需求是要根据前端请求的排序字段进行对结果相应的排序. 目标 实现根据排序要求返回排序后的结果 原理与思路 要实 ...

  4. 使用.NET 6开发TodoList应用(3)——引入第三方日志库

    需求 在我们项目开发的过程中,使用.NET 6自带的日志系统有时是不能满足实际需求的,比如有的时候我们需要将日志输出到第三方平台上,最典型的应用就是在各种云平台上,为了集中管理日志和查询日志,通常会选 ...

  5. 使用.NET 6开发TodoList应用(1)——系列背景

    前言 想到要写这样一个系列博客,初衷有两个:一是希望通过一个实践项目,将.NET 6 WebAPI开发的基础知识串联起来,帮助那些想要入门.NET 6服务端开发的朋友们快速上手,对使用.NET 6开发 ...

  6. 使用.NET 6开发TodoList应用(2)——项目结构搭建

    为了不影响阅读的体验,我把系列导航放到文章最后了,有需要的小伙伴可以直接通过导航跳转到对应的文章 : P TodoList需求简介 首先明确一下我们即将开发的这个TodoList应用都需要完成什么功能 ...

  7. 使用.NET 6开发TodoList应用(4)——引入数据存储

    需求 作为后端CRUD程序员(bushi,数据存储是开发后端服务一个非常重要的组件.对我们的TodoList项目来说,自然也需要配置数据存储.目前的需求很简单: 需要能持久化TodoList对象并对其 ...

  8. 使用.NET 6开发TodoList应用(5)——领域实体创建

    需求 上一篇文章中我们完成了数据存储服务的接入,从这一篇开始将正式进入业务逻辑部分的开发. 首先要定义和解决的问题是,根据TodoList项目的需求,我们应该设计怎样的数据实体,如何去进行操作? 长文 ...

  9. 使用.NET 6开发TodoList应用(5.1)——实现Repository模式

    需求 经常写CRUD程序的小伙伴们可能都经历过定义很多Repository接口,分别做对应的实现,依赖注入并使用的场景.有的时候会发现,很多分散的XXXXRepository的逻辑都是基本一致的,于是 ...

随机推荐

  1. HTTP请求 Java API

    1.导入依赖 <dependency> <groupId>commons-httpclient</groupId> <artifactId>common ...

  2. 【leetcode】208. Implement Trie (Prefix Tree 字典树)

    A trie (pronounced as "try") or prefix tree is a tree data structure used to efficiently s ...

  3. Linux基础命令---mget获取ftp文件

    mget 使用lftp登录mftp服务器之后,可以使用mget指令从服务器获取文件.mget指令可以使用通配符,而get指令则不可以.   1.语法       mget [-E]  [-a]  [- ...

  4. 软件测试人员必备的linux命令

    1 目录与文件操作1.1 ls(初级)使用权限:所有人功能 : 显示指定工作目录下之内容(列出目前工作目录所含之档案及子目录). 参数 : -a 显示所有档案及目录 (ls内定将档案名或目录名称开头为 ...

  5. window 查看端口占用情况

    查看哪个进程在用 netstat -aon|findstr "8080" TCP    0.0.0.0:8080           0.0.0.0:0              ...

  6. JSP中声明变量、方法

    在JSP页面中声明局部变量,全局变量,方法等 代码示例: <%@ page language="java" contentType="text/html; char ...

  7. Rust开发环境搭建和hello world工程

    windows10 WSL 打开wsl,执行以下命令 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 出现安装选项,选择1 ...

  8. 【代码优化】List.remove() 剖析

    一.犯错经历 1.1 故事背景 最近有个需求大致的背景类似: 我已经通过一系列的操作拿到一批学生的考试成绩数据,现在需要筛选成绩大于 95 分的学生名单. 善于写 bug 的我,三下五除二完成了代码的 ...

  9. VMware 安装Linux (以CentOS7-2009为例)

    1.VMware下载安装 链接:https://pan.baidu.com/s/11Y-AFB3aaAFxafdGPw4zaw 提取码:hskj 2.CentOS镜像官网下载:https://www. ...

  10. CF749B Parallelogram is Back 题解

    Content 给出平行四边形的三个顶点 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\),求出所有可能的第四个顶点. 数据范围:\(\forall i\in[1,3],-1000\ ...