当前位置: 首页 > news >正文

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

🚀 自动过滤:用 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.xdnf.cn/news/728101.html

相关文章:

  • 怎么从一台电脑拷贝已安装的所有python第三方库到另一台
  • 分库分表的常见策略
  • Arduino学习-跑马灯
  • day 26 函数专题
  • 基于云模型与TOPSIS评价算法的综合应用研究
  • 深度刨析树结构(从入门到入土讲解AVL树及红黑树的奥秘)
  • 深入理解Transformer架构:从原理到实践
  • python中 @注解 及内置注解 的使用方法总结以及完整示例
  • Jenkins 2.479.1安装和邮箱配置教程
  • SkyWalking如何实现跨线程Trace传递
  • 权威认证与质量保障:第三方检测在科技成果鉴定测试中的核心作用
  • 【C语言编译与链接】--翻译环境和运行环境,预处理,编译,汇编,链接
  • 怎么用外网打开内网的网址?如在异地在家连接访问公司局域网办公网站
  • DeepSeek 赋能数字人直播带货:技术革新重塑电商营销新生态
  • 处理知识库文件_编写powershell脚本文件_批量转换其他格式文件到pdf文件---人工智能工作笔记0249
  • Android 代码阅读环境搭建:VSCODE + SSH + CLANGD(详细版)
  • 生成式AI如何重塑设计思维与品牌创新?从工具到认知革命的跃迁
  • TCP通信与MQTT协议的关系
  • 使用ssh-audit扫描ssh过期加密算法配置
  • Qt实现csv文件按行读取的方式
  • ​什么是RFID电子标签​
  • 1. pytorch手写数字预测
  • 新能源集群划分+电压调节!基于分布式能源集群划分的电压调节策略!
  • 24位高精度数据采集卡NET8860音频振动信号采集监测满足自动化测试应用现场的多样化需求
  • DeepSeek-R1-0528
  • manus对比ChatGPT-Deep reaserch进行研究类论文数据分析!谁更胜一筹?
  • Google Play推出新功能:用户可直接向Gemini提问应用相关问题
  • 无人机多旋翼倾转动力测试系统-适用于(eVTOL开发、缩比模型测试、科研教育)
  • 成都鼎讯--通信干扰设备功能全解析
  • 经典SQL查询问题的练习第二天