Entity Framework Core中动态合并可变数量查询并单次执行的实现方法
Entity Framework Core中动态合并可变数量查询并单次执行的实现方法
我来帮你搞定这个问题!你当前的代码核心问题出在合并查询的逻辑错误上:Concat是无状态的扩展方法,它不会修改原有的查询对象,而是返回一个全新的合并后查询,但你根本没接收这个返回值;而且你把lastQuery重新赋值为当前selectQuery的操作,直接把之前的合并结果都丢弃了,最后自然只得到第一个查询的结果。
要实现动态合并任意数量的查询,并且单次数据库往返执行,我们只需要修正合并逻辑,让每次合并后的查询都被正确保留即可。下面是修复后的完整代码,我会顺便帮你优化一些细节:
public List<Valuation> GetValuations(List<GetValuationCriteria> valuationCriteriaList) { // 先处理空列表的边界情况,避免空引用异常 if (!valuationCriteriaList.Any()) { return new List<Valuation>(); } IQueryable<Valuation> combinedQuery = null; foreach (var criteria in valuationCriteriaList) { // 构建当前条件对应的查询 var selectQuery = DbContext.Valuations .Where(w => w.ActivityDate == criteria.ActivityDate && w.ValuationSourceId == criteria.ValuationSourceId && w.ActivityTypeId == criteria.ActivityTypeId && w.CurrencyId == criteria.CurrencyId && w.OrganizationHierarchyId == criteria.OrganizationHierarchyId && w.StatusCode == "A"); if (combinedQuery == null) { // 第一个查询直接作为初始合并查询 combinedQuery = selectQuery; } else { // 关键:将当前查询与已合并的查询拼接,并重写赋值给combinedQuery // 这里根据需求二选一: // 1. Concat = SQL的UNION ALL,直接拼接所有结果(包含重复项,性能更高) combinedQuery = combinedQuery.Concat(selectQuery); // 2. Union = SQL的UNION,自动去重结果(需要额外的去重逻辑,性能稍低) // combinedQuery = combinedQuery.Union(selectQuery); } } // 此时combinedQuery是一个完整的查询树,EF Core会将其翻译成单次SQL请求 return combinedQuery.ToList(); }
关键细节解释:
- 必须接收合并后的查询对象:EF Core的
Concat/Union方法不会修改原查询,只会返回新的合并查询,所以必须把这个返回值重新赋值给combinedQuery,才能逐步累积所有的查询条件。 - 边界情况处理:如果传入的条件列表为空,直接返回空列表,避免后续调用
ToList()时出现空引用异常。 - Union与Concat的选择:根据你的需求决定:
- 用
Concat(对应SQL的UNION ALL):直接拼接所有符合条件的记录,包含重复项,数据库执行效率更高。 - 用
Union(对应SQL的UNION):自动对合并后的结果去重,但数据库需要额外处理去重逻辑,性能略低。
- 用
- 单次数据库往返:合并后的
combinedQuery是一个完整的查询表达式树,EF Core会将其翻译成包含UNION/UNION ALL的单条SQL语句,当你调用ToList()时,只会发起一次数据库请求,所有合并逻辑在数据库端完成,完全符合你的需求。
另外,如果你后续想优化查询条件的构建,还可以把Where条件封装成表达式树,但当前的写法已经能完美解决你的核心需求了。
内容来源于stack exchange




