使用.NET 6开发TodoList应用(14)——实现查询过滤
2022/1/1 23:37:45
本文主要是介绍使用.NET 6开发TodoList应用(14)——实现查询过滤,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
系列导航及源代码
- 使用.NET 6开发TodoList应用文章索引
需求
在查询请求中,还有一类常见的场景是过滤查询,也就是有限制条件的查询,落在数据库层面就是常用的Where
查询子句。实现起来也很简单。
目标
实现查询过滤的功能
原理与思路
查询过滤的请求有两种方式,一种是采用POST
方法,将查询条件放在请求体中,但是这种方式实际上和Restful的动词语义产生了矛盾,从Restful API成熟度模型的角度来说,还停留在Level 1阶段(仅知道地址,不符合动词语义),详情参考理查森成熟度模型;还有一种方法是采用GET
方法,将查询条件放在查询字符串里,我们将采用第二种方式来实现。
实现
我们还是通过查询TodoItem
列表来演示查询过滤,和前面的文章一样,我们先来实现一个查询的Query
请求对象:
GetTodoItemsWithConditionQuery.cs
using AutoMapper; using AutoMapper.QueryableExtensions; using MediatR; using TodoList.Application.Common.Interfaces; using TodoList.Application.Common.Mappings; using TodoList.Application.Common.Models; using TodoList.Domain.Entities; using TodoList.Domain.Enums; namespace TodoList.Application.TodoItems.Queries.GetTodoItems; public class GetTodoItemsWithConditionQuery : IRequest<PaginatedList<TodoItemDto>> { public Guid ListId { get; set; } public bool? Done { get; set; } public PriorityLevel? PriorityLevel { get; set; } public int PageNumber { get; set; } = 1; public int PageSize { get; set; } = 10; } public class GetTodoItemsWithConditionQueryHandler : IRequestHandler<GetTodoItemsWithConditionQuery, PaginatedList<TodoItemDto>> { private readonly IRepository<TodoItem> _repository; private readonly IMapper _mapper; public GetTodoItemsWithConditionQueryHandler(IRepository<TodoItem> repository, IMapper mapper) { _repository = repository; _mapper = mapper; } public async Task<PaginatedList<TodoItemDto>> Handle(GetTodoItemsWithConditionQuery request, CancellationToken cancellationToken) { return await _repository .GetAsQueryable(x => x.ListId == request.ListId && (!request.Done.HasValue || x.Done == request.Done) && (!request.PriorityLevel.HasValue || x.Priority == request.PriorityLevel)) .OrderBy(x => x.Title) .ProjectTo<TodoItemDto>(_mapper.ConfigurationProvider) .PaginatedListAsync(request.PageNumber, request.PageSize); } }
甚至为了结合之前讲的请求校验,我们可以在这里增加一个校验规则:
GetTodoItemValidator.cs
using FluentValidation; namespace TodoList.Application.TodoItems.Queries.GetTodoItems; public class GetTodoItemValidator : AbstractValidator<GetTodoItemsWithConditionQuery> { public GetTodoItemValidator() { RuleFor(x => x.ListId).NotEmpty().WithMessage("ListId is required."); RuleFor(x => x.PageNumber).GreaterThanOrEqualTo(1).WithMessage("PageNumber at least greater than or equal to 1."); RuleFor(x => x.PageSize).GreaterThanOrEqualTo(1).WithMessage("PageSize at least greater than or equal to 1."); } }
接下来在TodoItemController
中实现请求处理,我们直接修改上一篇讲分页的那个请求成如下(如果在上一篇的基础上新增Action的话,会导致路由的歧义):
TodoItemController.cs
// 省略其他... [HttpGet] public async Task<ApiResponse<PaginatedList<TodoItemDto>>> GetTodoItemsWithCondition([FromQuery] GetTodoItemsWithConditionQuery query) { return ApiResponse<PaginatedList<TodoItemDto>>.Success(await _mediator.Send(query)); }
验证
启动Api
项目,执行创建TodoList
的请求:
请求仅携带Done
过滤条件时
-
请求
-
响应
请求仅携带PriorityLevel
过滤条件时
-
请求
-
响应
请求携带完整的过滤条件时
-
请求
-
响应
请求参数不合法时
-
请求
我将pageNumber传成了0。 -
响应
总结
对于查询过滤这个需求来说,实现起来还是很简单的,但是这里其实隐藏了一个很重要的问题:如果查询的参数太多,比如存在多个Guid
类型的字段过滤,URL的总长度是有可能超出浏览器或者服务器Host环境限制的,在这种情况下,我们是否还要坚持使用符合理查森成熟度模型Level 2的GET
请求呢?
关于这个问题的争论一直以来就没有停过,首先说我个人的结论:可以采用POST
的方式去变通,没必要为难自己(虽然这话肯定会引来Restful拥趸的嘲讽)。可是如果对成熟度有硬性的要求,我们如何实现?比较通用的解决方案是将一步GET
查询拆成两步GET
查询。但是更多的情况,是我认为如果出现了这种情况,就放弃Restful风格吧。
其实GraphQL才是王道。
参考资料
- 理查森成熟度模型
- GraphQL
这篇关于使用.NET 6开发TodoList应用(14)——实现查询过滤的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2022-03-01沐雪多租宝商城源码从.NetCore3.1升级到.Net6的步骤
- 2024-05-08首个适配Visual Studio平台的国产智能编程助手CodeGeeX正式上线!C#程序员必备效率神器!
- 2024-03-30C#设计模式之十六迭代器模式(Iterator Pattern)【行为型】
- 2024-03-29c# datetime tryparse
- 2024-02-21list find index c#
- 2024-01-24convert toint32 c#
- 2024-01-24Advanced .Net Debugging 1:你必须知道的调试工具
- 2024-01-24.NET集成IdGenerator生成分布式全局唯一ID
- 2024-01-23用CI/CD工具Vela部署Elasticsearch + C# 如何使用
- 2024-01-23.NET开源的简单、快速、强大的前后端分离后台权限管理系统