Entity Framework LINQ复杂查询多谓词合并实现员工多条件匹配组织查询
解决方案
针对你的需求,这里提供两种可直接落地的实现方案,均可以避免冗余嵌套的if判断,且生成的SQL执行效率和你手动拼写的最优逻辑一致,完全支持后续分页查询。
方案1:EF Core 3.0+ 极简写法
如果你使用的是EF Core 3.0及以上版本,直接将所有过滤条件合并到Any内部即可,空值判断会被EF自动优化,不会出现在最终生成的SQL中:
query = query.Where(o => o.Persons.Any(p => // 过滤项为空时条件自动为true,不参与过滤 (string.IsNullOrWhiteSpace(filter.Name) || p.Name.ToLower().Contains(filter.Name.ToLower())) && (string.IsNullOrWhiteSpace(filter.Firstname) || p.Firstname.ToLower().Contains(filter.Firstname.ToLower())) && (string.IsNullOrWhiteSpace(filter.ContactNummer) || p.ContactNumber.Contains(filter.ContactNummer)) ));
该写法没有额外依赖,代码简洁易读,新增过滤字段只需添加一行&& (空判断 || 过滤逻辑)即可。
方案2:通用动态表达式拼接方案
如果使用的是旧版本EF,或者希望获得更强的可扩展性,可以通过表达式树动态拼接人员过滤条件,完全避免嵌套判断:
第一步:先实现表达式合并的扩展方法
public static class ExpressionExtensions { /// <summary> /// 合并两个谓词表达式,逻辑为And /// </summary> public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) { var paramRebinder = new ParameterRebinder(right.Parameters[0], left.Parameters[0]); var rewrittenRightBody = paramRebinder.Visit(right.Body); return Expression.Lambda<Func<T, bool>>( Expression.AndAlso(left.Body, rewrittenRightBody), left.Parameters ); } /// <summary> /// 表达式参数重绑定器,解决两个表达式参数不同的问题 /// </summary> private class ParameterRebinder : ExpressionVisitor { private readonly ParameterExpression _oldParam; private readonly ParameterExpression _newParam; public ParameterRebinder(ParameterExpression oldParam, ParameterExpression newParam) { _oldParam = oldParam; _newParam = newParam; } protected override Expression VisitParameter(ParameterExpression node) { return node == _oldParam ? _newParam : base.VisitParameter(node); } } }
第二步:使用扩展方法动态构建查询
// 初始化人员过滤条件,默认恒为true Expression<Func<Person, bool>> personPredicate = p => true; // 逐个添加非空的过滤条件 if (!string.IsNullOrWhiteSpace(filter.Name)) { personPredicate = personPredicate.And(p => p.Name.ToLower().Contains(filter.Name.ToLower())); } if (!string.IsNullOrWhiteSpace(filter.Firstname)) { personPredicate = personPredicate.And(p => p.Firstname.ToLower().Contains(filter.Firstname.ToLower())); } if (!string.IsNullOrWhiteSpace(filter.ContactNummer)) { personPredicate = personPredicate.And(p => p.ContactNumber.Contains(filter.ContactNummer)); } // 将人员过滤条件应用到组织查询中 query = query.Where(o => o.Persons.Any(personPredicate));
该方案的扩展性极强,后续新增过滤字段只需要新增一个if判断即可,无需修改原有逻辑,且完全兼容所有支持LINQ表达式的ORM框架。
内容的提问来源于stack exchange,提问作者Arne
相关产品推荐
相关产品推荐

