自动过滤:用 AutoFilterer 实现高性能动态查询

article/2025/7/4 21:10:05

🚀 自动过滤:用 AutoFilterer 实现高性能动态查询


📚 目录

  • 🚀 自动过滤:用 AutoFilterer 实现高性能动态查询
    • 🧩 项目场景
    • 🌟 AutoFilterer 核心优势
    • 🎯 项目结构流程图
    • 🛠 快速集成
      • 1️⃣ 安装依赖
      • 2️⃣ 注册服务(Program.cs)
    • 🌱 初始化种子数据流程图
    • 3️⃣ 实体与过滤 DTO
    • 4️⃣ Controller 实现:请求 & 缓存流程图
    • 🌐 示例请求与响应
    • 🧪 单元测试示例(xUnit)
    • 📊 最佳实践小结


🧩 项目场景

在中大型 .NET Web API 项目中,数据查询过滤是高频且重复度极高的任务。传统方式下:

  • 每个字段都需写 Where 条件;
  • 多字段组合查询冗长、易错;
  • Swagger 接口测试缺乏一致性与自动生成文档;

因此,引入 AutoFilterer —— 一个属性驱动的 LINQ 表达式生成器,支持动态查询和 OpenAPI 自动展示,全面提升代码质量与开发效率。


🌟 AutoFilterer 核心优势

🧩 特性✨ 描述
属性驱动DTO 上声明过滤规则,自动生成表达式
无需手写摒弃手工 LINQ 代码
多条件支持字符串、区间、布尔、枚举、日期等
OpenAPI 3.0与 Swagger UI 无缝集成
高性能表达式缓存、延迟执行、支持 EF Core
支持分页内置 PaginationFilterBase

🎯 项目结构流程图

在这里插入图片描述


🛠 快速集成

1️⃣ 安装依赖

dotnet add package AutoFilterer.Extensions.Microsoft.DependencyInjection --version 3.1.0
dotnet add package AutoFilterer.Swagger --version 3.1.0
dotnet add package System.Linq.Dynamic.Core --version 1.6.5

2️⃣ 注册服务(Program.cs)

using AutoFilterer.Swagger;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;var builder = WebApplication.CreateBuilder(args);// 1. AutoFilterer + 表达式缓存
builder.Services.AddAutoFilterer(options =>
{options.EnableExpressionCache = true;
});// 2. Swagger 集成 AutoFilterer 参数
builder.Services.AddSwaggerGen(c =>
{c.UseAutoFiltererParameters();c.SwaggerDoc("v1", new() { Title = "Book API", Version = "v1" });
});// 3. EF Core:演示用 InMemory,生产可切换 SQL Server
builder.Services.AddDbContext<AppDbContext>(opt =>
{opt.UseInMemoryDatabase("BooksDb");// 生产示例:// opt.UseSqlServer(builder.Configuration.GetConnectionString("Default"));
});// 4. MVC + 全局 camelCase JSON 命名
builder.Services.AddControllers().AddJsonOptions(opts =>{opts.JsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;});// 5. 内存缓存,用于结果缓存
builder.Services.AddMemoryCache();var app = builder.Build();// Seed 数据
using (var scope = app.Services.CreateScope())
{var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();DbSeeder.Seed(db);
}// 中间件
app.UseSwagger();
app.UseSwaggerUI();
app.MapControllers();
app.Run();

🌱 初始化种子数据流程图

false
true
应用启动
创建 Scope
解析 DbContext
db.Books.Any?
执行 AddRange(Books)
SaveChanges()
种子数据完成

3️⃣ 实体与过滤 DTO

public class Book
{public Guid Id { get; set; }public string Title { get; set; }public string Author { get; set; }public DateTime PublishedDate { get; set; }public int PageCount { get; set; }
}
using AutoFilterer.Attributes;
using AutoFilterer.Types;
using System.ComponentModel.DataAnnotations;public class BookFilter : PaginationFilterBase
{[ToLowerContainsComparison]public string? Title { get; set; }[ToLowerContainsComparison]public string? Author { get; set; }[CompareTo(nameof(Book.PublishedDate), FilterType.GreaterThanOrEqual)]public DateTime? FromDate { get; set; }[CompareTo(nameof(Book.PublishedDate), FilterType.LessThanOrEqual)]public DateTime? ToDate { get; set; }[CompareTo(nameof(Book.PageCount), FilterType.GreaterThan)]public int? MinPages { get; set; }/// <summary>/// 支持动态排序,格式示例:"PublishedDate desc"/// </summary>public string? SortBy { get; set; }[Range(1, 100)]public override int PageSize { get; set; } = 10;
}

4️⃣ Controller 实现:请求 & 缓存流程图

hit
miss
客户端请求
BooksController
检查缓存
返回缓存结果
应用 ApplyFilter
应用动态排序
执行 CountAsync()
执行 Skip/Take & ToListAsync()
缓存结果
返回结果
[ApiController]
[Route("api/[controller]")]
public class BooksController : ControllerBase
{private readonly AppDbContext _db;private readonly ILogger<BooksController> _logger;private readonly IMemoryCache _cache;public BooksController(AppDbContext db,ILogger<BooksController> logger,IMemoryCache cache){_db = db;_logger = logger;_cache = cache;}[HttpGet]public async Task<ActionResult<PagedResult<Book>>> Get([FromQuery] BookFilter filter){string cacheKey = $"books_{filter.GetCacheKey()}_{filter.SortBy}";try{if (!_cache.TryGetValue(cacheKey, out PagedResult<Book> result)){// 1. 应用过滤器var query = _db.Books.ApplyFilter(filter);// 2. 动态排序(依赖 System.Linq.Dynamic.Core)if (!string.IsNullOrWhiteSpace(filter.SortBy))query = query.OrderBy(filter.SortBy);elsequery = query.OrderBy("PublishedDate desc");// 3. 分页 + 总数var total = await query.CountAsync();var items = await query.Skip((filter.PageNumber - 1) * filter.PageSize).Take(filter.PageSize).ToListAsync();result = new PagedResult<Book>(total, items);// 缓存 5 分钟_cache.Set(cacheKey, result, TimeSpan.FromMinutes(5));}return Ok(result);}catch (ArgumentException ex){_logger.LogWarning(ex, "Invalid filter parameter");return BadRequest("请求参数错误");}catch (DbUpdateException ex){_logger.LogError(ex, "Database update failure");return StatusCode(503, "服务暂不可用");}catch (Exception ex){_logger.LogError(ex, "Unexpected error");return StatusCode(500, "查询失败");}}
}// 分页结果模型
public record PagedResult<T>(int Total, List<T> Items);

🌐 示例请求与响应

GET /api/books?Author=alice&MinPages=110&SortBy=PageCount%20desc&PageSize=5&PageNumber=1
{"total": 25,"items": [{ "id": "guid", "title": "Book 48", "author": "Alice", "publishedDate": "2025-05-02T00:00:00", "pageCount": 148 },...]
}

🧪 单元测试示例(xUnit)

public class BookFilterTests
{[Fact]public void ApplyFilter_ShouldFilterByTitle(){// Arrangevar data = new[]{new Book { Title = "alice" },new Book { Title = "bob" }}.AsQueryable();var filter = new BookFilter { Title = "ali" };// Actvar result = data.ApplyFilter(filter).ToList();// AssertAssert.Single(result);Assert.Equal("alice", result[0].Title);}
}

📊 最佳实践小结

维度建议
性能开启表达式缓存;合理设置缓存过期
安全性DTO 参数加 [Range] 限制;细粒度异常返回
可维护性提取 DbSeederPagedResult<T>IBookRepository 等;分层结构
文档体验Mermaid 图导出为图片;示例请求/响应;代码高亮
扩展性动态排序(System.Linq.Dynamic.Core);分布式/共享缓存方案
可测试性单元测试覆盖过滤逻辑;集成测试验证 API 行为


http://www.hkcw.cn/article/EYDiCLJJyq.shtml

相关文章

haproxy 搭建web群集

一 案例分析 1.案例概述 目录 一 案例分析 1.案例概述 2.案例前置知识点 2.1 HTTP 请求 2.2 负载均衡常用调度算法 2.3 常见的web群集调度器 二 案例实施 1.安装网站 &#xff08;1&#xff09;关闭Linux防火墙 (2)安装网站httpd服务器 (3)添加网页 &#xff0…

华为OD机试真题——MELON的难题(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《MELON的难题》: 目录 题目…

巴黎为欧冠决赛部署5400名警力 防范球迷骚乱

巴黎警方于5月30日宣布,在5月31日晚举行的巴黎圣日耳曼对阵国际米兰的欧洲冠军联赛决赛期间,将在全城部署多达5400名警力,以防止过激球迷制造骚乱。尽管比赛在德国慕尼黑的安联球场举行,但预计大量球迷会在巴黎的公共区域内聚集观赛。如果巴黎圣日耳曼获胜,庆祝活动有可能…

图解gpt之Transformer架构与设计原理

Transformer架构。它不仅仅是一个模型&#xff0c;更是一种范式&#xff0c;彻底改变了我们理解和处理自然语言的方式。 2017年&#xff0c;谷歌大脑团队发表了一篇划时代的论文&#xff0c;题目就叫《Attention is All You Need》。这标题本身就充满了力量&#xff0c;宣告了…

【技能篇】Java 面试题大全

目录 1&#xff0e; JDK和 JRE 有什么区别? 2&#xff0e; 和equals 的区别是什么? 3&#xff0e; 两个对象的 hashCode()相同&#xff0c;则 equals()也一定为 true, 对吗? 4&#xff0e; final在java 中有什么作用? 5&#xff0e; java 中的Math.round(-1.5)等于多少…

RFID赋能零件智能夹取新生态

RFID赋能零件智能夹取新生态 山东某零件加工厂存在问题&#xff1a; &#xff08;1&#xff09;在复杂的生产流程中&#xff0c;零件种类繁多、尺寸各异&#xff0c;传统识别方式易出错且效率低下&#xff0c;难以满足高速、高精度生产需求&#xff1b; &#xff08;2&#…

CTFSHOW Pwn94 WP

checksec&#xff1a; 32位 保护只开了NX IDA32打开 查看函数&#xff1a; 可以进行多次的printf 存在system函数 用格式字符串漏洞 fmtstr_payload工具 劫持printf GOT为system PLT函数 偏移为6 exp&#xff1a; from pwn import * context.log_level debugp process(./p…

机器学习算法03:聚类算法

一、引言 聚类算法是一类无监督学习算法&#xff0c;旨在将数据集中的样本划分为多个组或簇&#xff0c;使得同一簇内的样本具有较高的相似性&#xff0c;而不同簇之间的样本具有较大的差异性。其主要作用是发现数据的内在结构和分布规律&#xff0c;为数据分析、模式识别、数…

洛谷习题V^V

1.帮贡排序 解题思路&#xff1a;按照题意&#xff0c;排序模拟即可 #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std;struct Member {string name;string position;int contribution;int level;…

女子称在酒店遗失婚戒 譤方回应:警方已介入调查

5月29日,周女士在深圳蛇口太子湾逸扉酒店住了一晚,不慎将价值6万多元的婚戒遗忘在床头柜上。她于次日在社交平台上发帖求助。据周女士描述,她在28日出差入住该酒店,晚上将婚戒放在床头柜,而她结婚还不满一个月。29日上午9点30分,她去餐厅吃早餐,10点30分退房,直到11点2…

【运维实战】Linux 中设置 sudo ,8个有用的 sudoers 配置!

在Linux及其他类Unix操作系统中&#xff0c;只有 root 用户能够执行所有命令并进行关键系统操作&#xff0c;例如安装更新软件包、删除程序、创建用户与用户组、修改重要系统配置文件等。 但担任 root 角色的系统管理员可通过配置sudo命令&#xff0c;允许普通系统用户执行特定…

Baklib智能推荐赋能内容中台升级

智能推荐重构内容中枢 现代内容中台正经历智能化推荐系统驱动的结构性变革&#xff0c;通过自然语言解析与用户行为建模技术实现信息处理范式的升级。该系统深度融合语义理解引擎&#xff0c;可对知识库中的操作指南、产品文档等非结构化数据进行动态解构&#xff0c;结合多维…

每日算法-250530

每日算法 - 250530 记录一下今天完成的LeetCode算法题目&#xff0c;包含思路、解题过程、复杂度分析和代码实现。 3128. 直角三角形 题目 思路 数组 解题过程 显而易见的是&#xff0c;我们枚举中间的顶点最好计算。当我们的中间顶点是1时&#xff0c;它能够组成的直角三角…

抽奖系统抽奖活动管理流程

抽奖系统大纲&#xff1a; 目录 抽奖系统大纲&#xff1a; 创建抽奖活动&#xff1a; 前端传入&#xff1a; 创建抽奖活动&#xff0c;需要圈选人员&#xff0c;圈选奖品&#xff0c;填写活动必要信息。 Controller层&#xff1a; 接收参数&#xff0c;调用服务层代码&a…

Grace《歌手》第三期第一 格瑞丝夺冠引领风潮

5月30日晚,《歌手2025》第三期播出,共有8名歌手参加比赛。排名如下:格瑞丝金斯勒获得第一名,单依纯位列第二,米奇盖顿排在第三,GAI周延第四,陈楚生第五,马嘉祺第六,白举纲第七。根据节目规则,若袭榜歌手获胜,本场竞演排名最末的在线歌手将暂别舞台。查理普斯作为首位…

郑钦文巴黎街头演唱《日不落》 甜蜜16强庆祝

北京时间5月30日,2025年法网进入第六个比赛日。中国球员郑钦文作为8号种子,以6比3、6比4战胜18岁的加拿大新星姆博科,顺利晋级16强,追平了她在法网的最佳战绩。赛后,郑钦文更新了多条动态,发布了一条微博:“甜蜜16强。”她还分享了一段视频,展示了自己在法国巴黎街头即…

华为OD机试真题——天然蓄水库(2025A卷:200分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 200分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析; 并提供Java、python、JavaScript、C++、C语言、GO六种语言的最佳实现方式! 2025华为OD真题目录+全流程解析/备考攻略/经验分享 华为OD机试真题《天然蓄水库》: 目录 题目…

基本数据指针的解读-C++

1、引言 笔者认为对于学习指针要弄清楚如下问题基本可以应付大部分的场景&#xff1a; ① 指针是什么&#xff1f; ② 指针的类型是什么&#xff1f; ③ 指针指向的类型是什么&#xff1f; ④ 指针指向了哪里&#xff1f; 2、如何使用指针 使用时的步骤如下&#xff1a; ① …

日志技术-LogBack、Logback快速入门、Logback配置文件、Logback日志级别

一. 日志技术 1. 程序中的日志&#xff0c;是用来记录应用程序的运行信息、状态信息、错误信息等。 2. JUL&#xff1a;(java.util.logging)这是JavaSE平台提供的官方日志框架&#xff0c;也被称为JUL。配置相对简单&#xff0c;但不够灵活&#xff0c;性能较差。 3.Logs4j&…

Nuxt多环境配置

前言 多环境配置对于特定环境新增、更新、删除配置相当重要&#x1f601;而且不需要人为去变更配置减少出错 实践 方案1&#xff08;官方推荐&#xff09; 升级依赖 升级Nuxt到最新版&#xff08;3.15.x只有开发和生产配置&#xff0c;不支持自定义环境&#xff09; npx n…