C#中如何通过LINQ实现多业务单元条件的批量记录查询?
多业务单元筛选问题解决方法
问题描述
我开发了支持多条件筛选的前端,其中包含业务单元(Business Units)筛选项。单业务单元筛选时,URL为https://localhost:7206/api/v1/lots?businessUnits=SCP_PP,功能正常。现在需要实现多业务单元筛选,URL格式为https://localhost:7206/api/v1/lots?businessUnits=SCP_PP%2CNAG,该参数在C#后端接收为字符串"SCP_PP, NAG"。尝试通过拆分字符串为数组,循环添加Where条件,但无法返回符合多条件的记录(单条件筛选正常)。
原查询实现代码:
public List<Lot> GetLots(DateTime? dateFrom, DateTime? dateTo, bool? includeGraded, string? status, string? businessUnits) { var lots = _gradingContext.Lots.AsNoTracking().AsQueryable(); if(businessUnits!= null) { if (businessUnits.Contains(',')) { string[] businessUnitsTemp = businessUnits.Split(","); foreach (var unit in businessUnitsTemp) { lots = lots.Where(x => x.BusinessUnit.Equals(businessUnitsTemp)); } } else { lots = lots.Where(x => x.BusinessUnit.Equals(businessUnits)); } } return lots.ToList(); }
问题根源
- 循环条件错误:循环中误将数组
businessUnitsTemp作为匹配值,而非当前循环的unit变量,导致筛选逻辑完全失效。 - 未处理空格:后端接收的参数是"SCP_PP, NAG",拆分后第二个元素带前置空格,无法匹配数据库中的"NAG"。
- 逻辑错误:循环叠加
Where条件会生成**逻辑与(AND)规则,要求记录同时匹配所有业务单元,而实际需要的是逻辑或(OR)**规则。
修正方案
方案1:使用Contains实现简单OR筛选(推荐)
直接用集合的Contains方法替代循环,简洁高效:
public List<Lot> GetLots(DateTime? dateFrom, DateTime? dateTo, bool? includeGraded, string? status, string? businessUnits) { var lots = _gradingContext.Lots.AsNoTracking().AsQueryable(); if (!string.IsNullOrEmpty(businessUnits)) { // 拆分参数、去除空格、过滤空值 var businessUnitList = businessUnits.Split(',') .Select(unit => unit.Trim()) .Where(unit => !string.IsNullOrEmpty(unit)) .ToList(); if (businessUnitList.Any()) { // 筛选BusinessUnit在列表中的记录(OR逻辑) lots = lots.Where(x => businessUnitList.Contains(x.BusinessUnit)); } } // 其他筛选逻辑... return lots.ToList(); }
方案2:使用PredicateBuilder实现复杂OR筛选
如果后续需要扩展更复杂的OR条件,可以借助LinqKit的PredicateBuilder(需先安装LinqKit NuGet包):
using LinqKit; public List<Lot> GetLots(DateTime? dateFrom, DateTime? dateTo, bool? includeGraded, string? status, string? businessUnits) { var lots = _gradingContext.Lots.AsNoTracking().AsQueryable(); if (!string.IsNullOrEmpty(businessUnits)) { var businessUnitList = businessUnits.Split(',') .Select(unit => unit.Trim()) .Where(unit => !string.IsNullOrEmpty(unit)) .ToList(); if (businessUnitList.Any()) { var predicate = PredicateBuilder.New<Lot>(false); foreach (var unit in businessUnitList) { var currentUnit = unit; // 捕获循环变量,避免闭包陷阱 predicate = predicate.Or(x => x.BusinessUnit.Equals(currentUnit)); } lots = lots.Where(predicate); } } // 其他筛选逻辑... return lots.ToList(); }
关键注意事项
- 必须处理参数中的空格:前端传参解码后带空格,
Trim()是匹配数据库值的前提。 - 过滤空元素:避免参数末尾带逗号导致拆分出空字符串,干扰筛选结果。
- 闭包陷阱:使用
PredicateBuilder循环时,需将循环变量赋值给局部变量,否则所有条件会复用最后一个循环值。
内容的提问来源于stack exchange,提问作者shizz
相关产品推荐
相关产品推荐

