You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# IQueryable Union操作后排序丢失,如何保留排序?

解决Union操作后排序丢失的问题

为什么排序会丢失

Union是集合去重合并操作,EF Core会将其转换为SQL的UNION语句,而SQL标准中UNION的结果是无序的——无论子查询有没有排序,最终结果都会忽略这些排序规则,只有在整个查询的末尾添加ORDER BY才能确保最终结果的顺序。另外,你之前在子查询中添加的排序完全多余,既不影响Union结果,还会增加不必要的查询开销。

方案一:统一最终排序(不区分匹配优先级)

如果不需要按“匹配字段的重要性”排序,只需要统一的排序规则,可去掉所有子查询的排序,先合并去重,再在最后添加全局排序:

var expressions = new List<IQueryable<Container>>();

var containers1 = containers
    .Where(x => EF.Functions.Like(x.ContainerReference1, $"%{message.SearchValue}%")
             || EF.Functions.Like(x.ContainerReference2, $"%{message.SearchValue}%"));
expressions.Add(containers1);

var containers2 = containers
                  .Where(x => EF.Functions.Like(x.Description, $"%{message.SearchValue}%"));
expressions.Add(containers2);

var containers3 = containers.Where(x => x.ContactEmails
                            .Any(y => EF.Functions.Like(y.Email, $"%{message.SearchValue}%")
                                 || EF.Functions.Like(y.DisplayName, $"%{message.SearchValue}%")));
expressions.Add(containers3);

var containers4 = containers
                            .Where(x => EF.Functions.Like(x.Keywords, $"%{message.SearchValue}%"));
expressions.Add(containers4);

// 先合并去重,再执行全局排序
containers = expressions.Aggregate((acc, i) => acc.Union(i))
                        .OrderBy(x => x.ContainerReference1)
                        .ThenBy(x => x.ContainerReference2)
                        .ThenByDescending(x => x.DateUpdated);

方案二:按匹配优先级排序(区分匹配字段的重要性)

如果希望优先展示匹配容器编号的结果,再展示匹配描述的,以此类推,可以给每个匹配结果添加优先级权重,合并后按优先级排序,再补充其他排序规则:

// 每个子查询添加优先级标识,数字越小优先级越高
var containers1 = containers
    .Where(x => EF.Functions.Like(x.ContainerReference1, $"%{message.SearchValue}%")
             || EF.Functions.Like(x.ContainerReference2, $"%{message.SearchValue}%"))
    .Select(x => new { Container = x, Priority = 1 });

var containers2 = containers
                  .Where(x => EF.Functions.Like(x.Description, $"%{message.SearchValue}%"))
                  .Select(x => new { Container = x, Priority = 2 });

var containers3 = containers.Where(x => x.ContactEmails
                            .Any(y => EF.Functions.Like(y.Email, $"%{message.SearchValue}%")
                                 || EF.Functions.Like(y.DisplayName, $"%{message.SearchValue}%")))
                            .Select(x => new { Container = x, Priority = 3 });

var containers4 = containers
                            .Where(x => EF.Functions.Like(x.Keywords, $"%{message.SearchValue}%"))
                            .Select(x => new { Container = x, Priority = 4 });

// 合并所有结果,按主键去重(避免同一个容器匹配多个条件),再排序
var combined = containers1
    .Union(containers2)
    .Union(containers3)
    .Union(containers4)
    .GroupBy(item => item.Container.Id) // 假设Id是Container的主键,用于去重
    .Select(g => g.First()) // 保留优先级最高的匹配项
    .OrderBy(item => item.Priority) // 先按优先级排序
    .ThenBy(item => item.Container.ContainerReference1)
    .ThenBy(item => item.Container.ContainerReference2)
    .ThenByDescending(item => item.Container.DateUpdated)
    .Select(item => item.Container);

containers = combined;

额外优化点

子查询containers3里对ContactEmails的OrderBy完全多余,因为Any只需要判断是否存在匹配项,排序不会影响结果,去掉后能提升查询性能。

内容的提问来源于stack exchange,提问作者A. Gladkiy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:55:06