基于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
相关产品推荐
相关产品推荐

