使用EF+LINQ实现通配符搜索的更优实现方案咨询
你当前的写法可以实现需求,但存在两个可优化点:一是多搜索条件时代码重复度高,可读性差;二是即便搜索条件为空,三元判断逻辑仍会被带入表达式树,部分低版本EF生成的SQL会携带冗余的1=1判断,虽不影响执行结果,但性能和简洁性都有提升空间。
最优通用方案:封装WhereIf扩展方法
这是.NET生态中处理动态搜索条件的通用实现,兼具性能和简洁性:
第一步:实现通用扩展方法
using System.Linq.Expressions; public static class QueryableExtensions { /// <summary> /// 条件成立时才执行Where过滤 /// </summary> /// <param name="source">待过滤的IQueryable数据源</param> /// <param name="condition">是否执行过滤的判断条件</param> /// <param name="predicate">过滤谓词</param> public static IQueryable<T> WhereIf<T>(this IQueryable<T> source, bool condition, Expression<Func<T, bool>> predicate) { return condition ? source.Where(predicate) : source; } // 如果需要处理内存集合的过滤,可以再加IEnumerable版本的重载 public static IEnumerable<T> WhereIf<T>(this IEnumerable<T> source, bool condition, Func<T, bool> predicate) { return condition ? source.Where(predicate) : source; } }
第二步:业务代码调用
data = data .WhereIf(!string.IsNullOrEmpty(searchCriteria1), p => p.field1.Contains(searchCriteria1)) .WhereIf(!string.IsNullOrEmpty(searchCriteria2), p => p.field2.Contains(searchCriteria2));
优势
- 代码简洁:多条件场景下不需要重复写三元判断或大量if块,维护成本低
- 性能最优:条件不成立时完全不会将过滤逻辑加入表达式树,EF生成的SQL没有任何冗余判断,执行效率最高
- 通用性强:不止可以处理字符串空值的判断,所有动态条件(比如数值范围、日期过滤等)都可以用这个扩展方法
进阶优化:针对字符串模糊搜索的专属扩展
如果你的业务中存在大量字符串包含查询的场景,可以再封装一层更简化的扩展,连Contains逻辑都不用重复写:
public static IQueryable<T> WhereContainsIfNotEmpty<T>(this IQueryable<T> source, string searchValue, Expression<Func<T, string>> fieldSelector) { if (string.IsNullOrEmpty(searchValue)) return source; // 动态构造 p => p.字段.Contains(searchValue) 的表达式 var parameter = fieldSelector.Parameters[0]; var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) }); var fieldAccess = fieldSelector.Body; var searchConstant = Expression.Constant(searchValue, typeof(string)); var containsCall = Expression.Call(fieldAccess, containsMethod, searchConstant); var predicate = Expression.Lambda<Func<T, bool>>(containsCall, parameter); return source.Where(predicate); }
调用时更加简洁:
data = data .WhereContainsIfNotEmpty(searchCriteria1, p => p.field1) .WhereContainsIfNotEmpty(searchCriteria2, p => p.field2);
内容的提问来源于stack exchange,提问作者Hashan S.
相关产品推荐
相关产品推荐

