如何在IQueryable循环中为Entity Framework Core实现WHERE OR查询
实现方案
完全可以实现,你需要手动构造表达式树完成OR逻辑拼接,核心逻辑是将多个条件表达式通过Expression.OrElse组合后,一次性传入Where方法,替代循环叠加Where的写法。
前置准备:表达式拼接辅助方法
因为不同Lambda表达式的参数实例不同,直接拼接会报错,需要先实现一个参数重绑定的辅助方法,用于统一多个条件的参数:
using System.Linq.Expressions; public static class ExpressionExtensions { public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right) { var visitor = new ParameterRebinder(right.Parameters[0], left.Parameters[0]); var rightBody = visitor.Visit(right.Body); return Expression.Lambda<Func<T, bool>>(Expression.OrElse(left.Body, rightBody), left.Parameters); } 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); } } }
改造后的业务代码
你原有的循环逻辑需要调整为先收集所有条件,再统一拼接:
// 先获取所有选中的配置项 var selectedRfsList = newsItemQuery.MyData.Where(x => x.Selected).ToList(); // 初始化OR拼接的起始条件,false不会影响后续OR逻辑的结果 Expression<Func<YourEntityType, bool>> predicate = _ => false; foreach (var rfs in selectedRfsList) { Expression<Func<YourEntityType, bool>> currentCondition = null; if (!rfs.IncludeNegative && !rfs.IncludeNeutral) { currentCondition = x => x.Id == rfs.Id && !x.IsNegative && !x.IsNeutral; } else if (!rfs.IncludeNegative && rfs.IncludeNeutral) { currentCondition = x => x.Id == rfs.Id && !x.IsNegative; } else if (rfs.IncludeNegative && !rfs.IncludeNeutral) { currentCondition = x => x.Id == rfs.Id && !x.IsNeutral; } else { currentCondition = x => x.Id == rfs.Id; } // 拼接OR逻辑 predicate = predicate.Or(currentCondition); } // 最后一次性将组合好的条件传入Where queryable = queryable.Where(predicate);
注意:请把代码中的YourEntityType替换为你实际查询的实体类类型
可选简化方案
如果你不排斥引入轻量工具库,也可以直接用LinqKit的PredicateBuilder类,不需要自己实现上述扩展方法,用法和上面的逻辑完全一致,仅需把初始条件改成var predicate = PredicateBuilder.New<YourEntityType>(false);即可。
验证说明
上述方式生成的表达式树可以被EF Core正确翻译为SQL中的WHERE (条件1) OR (条件2) OR (条件3)...结构,不会产生客户端评估问题,性能和手写单条Where查询一致。
内容的提问来源于stack exchange,提问作者YodasMyDad
相关产品推荐
相关产品推荐

