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

基于LINQ实现PartOrders与ServiceOrders的分组关联查询需求

LINQ查询方案:合并分组后的PartOrders与ServiceOrders

需求说明

现有两个列表PartOrders和ServiceOrders,存在多个orderNumber相同且createdDate为同一天的条目。需要完成以下操作:

  • 对两个列表分别按orderNumber和createdDate的日期部分分组,每个分组保留唯一的orderNumber、createdDate,其余数据封装为对应子列表
  • 匹配两个列表中orderNumber相同的分组,合并生成Result类型的列表

必要类定义

首先补充Result类依赖的两个子数据类:

public class TheRestOfOrdersData
{
    public string orderDescription { get; set; }
    public string OderNote { get; set; }
}

public class TheRestOfServiceData
{
    public string ServiceDescription { get; set; }
    public string ServiceNote { get; set; }
}

原有的实体类和结果类:

public class PartOrders
{
    public string orderNumber{ get; set; }
    public DateTime createdDate { get; set; }
    public string orderDescription { get; set; }
    public string OderNote { get; set; }
}

public class ServiceOrders
{
    public string orderNumber{ get; set; }
    public DateTime createdDate { get; set; }
    public string ServiceDescription { get; set; }
    public string ServiceNote { get; set; }
}

public class Result
{
    public string orderNumber{ get; set; }
    public DateTime createdDate { get; set; }
    public List<TheRestOfOrdersData> theRestOfOrdersData  { get; set; }
    public List<TheRestOfServiceData> theRestOfServiceData{ get; set; }    
}

LINQ实现代码

步骤1:对两个列表分组处理

先将PartOrders和ServiceOrders分别分组,提取分组键和剩余数据:

// 分组PartOrders:按orderNumber和createdDate的日期部分分组
var groupedParts = partOrder.GroupBy(p => new 
{ 
    p.orderNumber, 
    CreatedDate = p.createdDate.Date // 仅取日期部分,确保同一天的条目归为一组
})
.Select(g => new 
{
    g.Key.orderNumber,
    g.Key.CreatedDate,
    PartData = g.Select(p => new TheRestOfOrdersData 
    {
        orderDescription = p.orderDescription,
        OderNote = p.OderNote
    }).ToList()
});

// 分组ServiceOrders:逻辑同上
var groupedServices = serviceOrders.GroupBy(s => new 
{ 
    s.orderNumber, 
    CreatedDate = s.createdDate.Date
})
.Select(g => new 
{
    g.Key.orderNumber,
    g.Key.CreatedDate,
    ServiceData = g.Select(s => new TheRestOfServiceData 
    {
        ServiceDescription = s.ServiceDescription,
        ServiceNote = s.ServiceNote
    }).ToList()
});

步骤2:合并分组结果(全外连接)

使用全外连接匹配两个分组集合,生成最终的Result列表:

var results = groupedParts
    // 全外连接分组后的零件订单和服务订单
    .FullOuterJoin(groupedServices,
        p => p.orderNumber,
        s => s.orderNumber,
        (p, s) => new 
        {
            OrderNumber = p?.orderNumber ?? s?.orderNumber,
            CreatedDate = p?.CreatedDate ?? s?.CreatedDate ?? DateTime.MinValue,
            PartList = p?.PartData ?? new List<TheRestOfOrdersData>(),
            ServiceList = s?.ServiceData ?? new List<TheRestOfServiceData>()
        })
    // 转换为Result类型
    .Select(item => new Result
    {
        orderNumber = item.OrderNumber,
        createdDate = item.CreatedDate,
        theRestOfOrdersData = item.PartList,
        theRestOfServiceData = item.ServiceList
    })
    .OrderBy(r => r.orderNumber) // 按订单号排序,可选
    .ToList();

补充:FullOuterJoin扩展方法

如果系统没有自带全外连接方法,需要自定义扩展方法:

public static class LinqExtensions
{
    public static IEnumerable<TResult> FullOuterJoin<TLeft, TRight, TKey, TResult>(
        this IEnumerable<TLeft> left,
        IEnumerable<TRight> right,
        Func<TLeft, TKey> leftKeySelector,
        Func<TRight, TKey> rightKeySelector,
        Func<TLeft, TRight, TResult> resultSelector)
    {
        var leftLookup = left.ToLookup(leftKeySelector);
        var rightLookup = right.ToLookup(rightKeySelector);

        var allKeys = leftLookup.Select(g => g.Key).Union(rightLookup.Select(g => g.Key));

        foreach (var key in allKeys)
        {
            foreach (var leftItem in leftLookup[key])
            {
                foreach (var rightItem in rightLookup[key])
                {
                    yield return resultSelector(leftItem, rightItem);
                }
                if (!rightLookup.Contains(key))
                {
                    yield return resultSelector(leftItem, default);
                }
            }
            if (!leftLookup.Contains(key))
            {
                foreach (var rightItem in rightLookup[key])
                {
                    yield return resultSelector(default, rightItem);
                }
            }
        }
    }
}

示例数据验证

使用提供的示例数据运行上述代码后,会生成符合预期的Result列表:

  • 订单号1001:仅包含零件订单数据,服务订单列表为空
  • 订单号1002:包含2条零件订单数据和1条服务订单数据
  • 订单号1003:包含1条零件订单数据和2条服务订单数据
  • 订单号1004:仅包含零件订单数据
  • 订单号1000、1005:仅包含服务订单数据

内容的提问来源于stack exchange,提问作者Junior.netare

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 18:25:22