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

告别硬编码!用SqlSugar的IConditionalModel和WhereIF实现C#动态查询(附完整代码示例)

告别硬编码!用SqlSugar的IConditionalModel和WhereIF实现C#动态查询(附完整代码示例)

在后台管理系统、报表工具或搜索功能的开发中,动态查询是最常见的需求之一。用户可能根据不同的筛选条件组合查询数据,而开发者需要灵活应对这些变化。传统的字符串拼接SQL或复杂的Expression动态构建不仅难以维护,还存在SQL注入风险。本文将深入探讨如何利用SqlSugar的IConditionalModel和WhereIF,提供一套安全、可维护的动态查询方案。

1. 动态查询的常见痛点与解决方案

开发中我们常遇到这样的场景:用户在前端选择不同的筛选条件,后端需要根据这些条件动态构建查询。比如一个电商后台,管理员可能根据商品名称、价格范围、库存状态等任意组合查询商品。

传统解决方案主要有三种:

  1. 字符串拼接SQL:直接拼接SQL字符串,简单但存在SQL注入风险,且难以维护。
  2. 动态构建Expression:使用Expression树动态构建查询条件,类型安全但代码复杂。
  3. 链式调用Where:根据条件逐个调用Where方法,代码清晰但条件组合复杂时难以处理。

SqlSugar提供了两种更优雅的方案:IConditionalModelWhereIF。下面我们通过实际案例对比这几种方式的优劣。

// 字符串拼接SQL(不推荐) string sql = "SELECT * FROM Products WHERE 1=1"; if (!string.IsNullOrEmpty(name)) sql += $" AND Name LIKE '%{name}%'"; // SQL注入风险! // 动态Expression(复杂) Expression<Func<Product, bool>> expr = p => true; if (!string.IsNullOrEmpty(name)) expr = expr.And(p => p.Name.Contains(name)); // 链式Where(条件多时冗长) var query = db.Queryable<Product>(); if (!string.IsNullOrEmpty(name)) query = query.Where(p => p.Name.Contains(name));

2. 使用WhereIF简化条件查询

WhereIF是SqlSugar提供的一个非常实用的方法,它只在第一个参数为true时应用后面的查询条件。这种方式比传统的if判断更加简洁。

public ISugarQueryable<T> WhereIF(bool isWhere, Expression<Func<T, bool>> expression)

2.1 基础用法

假设我们有一个产品查询接口,支持按名称、价格范围和库存状态筛选:

public List<Product> SearchProducts(string name, decimal? minPrice, decimal? maxPrice, bool? inStock) { return db.Queryable<Product>() .WhereIF(!string.IsNullOrEmpty(name), p => p.Name.Contains(name)) .WhereIF(minPrice.HasValue, p => p.Price >= minPrice.Value) .WhereIF(maxPrice.HasValue, p => p.Price <= maxPrice.Value) .WhereIF(inStock.HasValue, p => p.Stock > 0 == inStock.Value) .ToList(); }

提示:WhereIF的条件判断应该尽可能简单,复杂逻辑建议提前计算好bool值再传入。

2.2 多条件组合

WhereIF也支持更复杂的条件组合,比如同时满足多个条件才应用查询:

bool shouldFilterPrice = minPrice.HasValue || maxPrice.HasValue; return db.Queryable<Product>() .WhereIF(!string.IsNullOrEmpty(name), p => p.Name.Contains(name)) .WhereIF(shouldFilterPrice, p => (!minPrice.HasValue || p.Price >= minPrice.Value) && (!maxPrice.HasValue || p.Price <= maxPrice.Value)) .ToList();

3. 使用IConditionalModel实现动态查询

对于更复杂的动态查询场景,特别是条件需要动态生成时,IConditionalModel提供了更大的灵活性。SqlSugar内置了两种实现:ConditionalModelConditionalCollections

3.1 ConditionalModel基础用法

ConditionalModel表示一个简单的查询条件,包含字段名、值和比较类型:

public class ConditionalModel : IConditionalModel { public string FieldName { get; set; } // 字段名 public string FieldValue { get; set; } // 值 public ConditionalType ConditionalType { get; set; } // 比较类型 }

常见比较类型包括:

  • Equal:等于
  • Like:模糊匹配
  • GreaterThan:大于
  • LessThan:小于
  • In:在集合中

示例代码:

var conditions = new List<IConditionalModel> { new ConditionalModel { FieldName = "Name", FieldValue = "手机", ConditionalType = ConditionalType.Like }, new ConditionalModel { FieldName = "Price", FieldValue = "1000", ConditionalType = ConditionalType.GreaterThan } }; var products = db.Queryable<Product>().Where(conditions).ToList();

3.2 处理复杂条件组合

ConditionalCollections允许我们构建更复杂的条件逻辑(AND/OR组合):

var complexCondition = new ConditionalCollections { ConditionalList = new List<KeyValuePair<WhereType, ConditionalModel>> { new KeyValuePair<WhereType, ConditionalModel>( WhereType.And, new ConditionalModel { FieldName = "Category", FieldValue = "1", ConditionalType = ConditionalType.Equal }), new KeyValuePair<WhereType, ConditionalModel>( WhereType.Or, new ConditionalModel { FieldName = "Price", FieldValue = "500", ConditionalType = ConditionalType.LessThan }), new KeyValuePair<WhereType, ConditionalModel>( WhereType.Or, new ConditionalModel { FieldName = "Stock", FieldValue = "0", ConditionalType = ConditionalType.GreaterThan }) } }; // 生成的SQL类似:WHERE (Category = 1) OR (Price < 500) OR (Stock > 0) var results = db.Queryable<Product>().Where(complexCondition).ToList();

3.3 动态构建查询条件

在实际应用中,我们通常需要根据用户输入动态构建条件。下面是一个完整的动态查询示例:

public List<Product> DynamicQuery(Dictionary<string, string> filters) { var conditions = new List<IConditionalModel>(); foreach (var filter in filters) { if (string.IsNullOrEmpty(filter.Value)) continue; var condition = new ConditionalModel { FieldName = filter.Key, FieldValue = filter.Value }; // 根据字段类型设置不同的比较方式 switch (filter.Key) { case "Name": condition.ConditionalType = ConditionalType.Like; break; case "Price": condition.ConditionalType = decimal.TryParse(filter.Value, out _) ? ConditionalType.Equal : ConditionalType.NoEqual; break; case "Stock": condition.ConditionalType = ConditionalType.GreaterThan; break; default: condition.ConditionalType = ConditionalType.Equal; break; } conditions.Add(condition); } return conditions.Count > 0 ? db.Queryable<Product>().Where(conditions).ToList() : db.Queryable<Product>().ToList(); }

4. 高级技巧与最佳实践

4.1 性能优化建议

动态查询虽然灵活,但也需要注意性能问题:

  1. 避免过度使用OR条件:大量OR条件可能导致索引失效
  2. 合理使用参数化查询:IConditionalModel会自动参数化,但直接拼接SQL不会
  3. 考虑分页:大数据量查询务必配合分页使用
// 好的实践:分页+条件 var pagedResult = db.Queryable<Product>() .Where(conditions) .ToPageList(pageNumber, pageSize);

4.2 与Entity Framework对比

相比于EF Core的动态查询方案,SqlSugar的IConditionalModel有几个优势:

特性SqlSugar IConditionalModelEF Core 动态LINQ
学习曲线
条件组合灵活性
性能
可维护性
原生SQL支持有限

4.3 实际项目中的应用模式

在实际项目中,我通常会采用以下模式组织动态查询代码:

public class ProductQueryBuilder { private readonly List<IConditionalModel> _conditions = new(); public ProductQueryBuilder WithName(string name) { if (!string.IsNullOrEmpty(name)) _conditions.Add(new ConditionalModel { FieldName = nameof(Product.Name), FieldValue = name, ConditionalType = ConditionalType.Like }); return this; } public ProductQueryBuilder WithPriceRange(decimal? min, decimal? max) { if (min.HasValue) _conditions.Add(new ConditionalModel { FieldName = nameof(Product.Price), FieldValue = min.Value.ToString(), ConditionalType = ConditionalType.GreaterThan }); if (max.HasValue) _conditions.Add(new ConditionalModel { FieldName = nameof(Product.Price), FieldValue = max.Value.ToString(), ConditionalType = ConditionalType.LessThan }); return this; } public ISugarQueryable<Product> Build(ISqlSugarClient db) { return _conditions.Count > 0 ? db.Queryable<Product>().Where(_conditions) : db.Queryable<Product>(); } } // 使用示例 var query = new ProductQueryBuilder() .WithName("手机") .WithPriceRange(1000, 5000) .Build(db); var results = query.ToList();

这种建造者模式让代码更加清晰,也便于单元测试。

http://www.jsqmd.com/news/790372/

相关文章:

  • Navicat重置试用期脚本:3分钟实现Mac版Navicat无限试用终极指南
  • CAPL中Seed2Key算法DLL封装与安全调用实践
  • Cwtch:基于Tor与双棘轮算法的去中心化隐私通信协议构建指南
  • 大麦网Python抢票脚本终极指南:告别黄牛票的完整解决方案
  • VoiceFixer完整指南:终极AI语音修复工具快速入门教程
  • 如何构建企业级文档转换系统:3大配置管理策略深度解析
  • 保姆级教程:用VMware双网卡配置,让开发板直连电脑调试时,电脑和虚拟机还能正常上网
  • AI原生测试生成自动化落地全景图(2026奇点大会闭门报告首次解禁)
  • 微信小程序集成ChatGPT:前端架构、流式响应与安全代理实践
  • 遗传算法在知识提取中的应用:Memgentic项目解析与实践
  • Taotoken的计费透明性让每一次调用都心中有数
  • 从HDLbits的Counter 1000到序列检测器:新手如何用Verilog搭建自己的第一个数字系统
  • 从GEO到建站,苏州网站建设优化公司推荐:十家公司服务商外贸站建设按场景适配 - 速递信息
  • 解锁AMD Ryzen终极潜能:5分钟掌握SMUDebugTool免费超频神器
  • 钉钉机器人如何配置 IP 白名单防止 Webhook 地址泄露?
  • tgfmcp:命令行文件直传Telegram,提升运维自动化效率
  • Navicat无限试用终极指南:三步彻底解决14天限制困扰
  • TI C2000 DSP双核怎么玩?手把手配置28377D的双核与CLA,榨干实时控制性能
  • 中兴光猫工厂模式解锁指南:3步掌握zteOnu高级配置技巧
  • 实用指南:如何使用SingleFile高效保存完整网页为单个HTML文件
  • 从报名到闭门签约:2026 AI大会VIP全流程图谱(含时间节点倒计时、材料预审checklist与合规红线清单)
  • 前端应用通过环境变量隐藏式接入 Taotoken 大模型服务
  • 如何高效实现AI驱动的浏览器自动化:Playwright MCP完整指南
  • 具身智能新突破:AI驱动机器人迈向真实世界
  • 从理论到实践:ISO27001风险评估的完整落地指南
  • StardewXnbHack:如何在43秒内解锁星露谷物语的全部游戏资源?
  • Seata事务日志存文件还是数据库?file.conf里store.mode=db的完整配置与性能调优指南
  • 【紧急预警】2025年Q2起,未适配SITS 2026语义协议的IDE插件将无法调用新发布的CodeTrust签名验证API——这份兼容性迁移清单你必须今晚看完
  • 告别Visual Studio!用JetBrains Rider for Unreal Engine 4.25+ 写C++代码有多爽?
  • 【DeepSeek实战】基于 V4 的企业级 RAG 系统:私有知识库问答实战