如何通过LINQ从SQL Server结果集中分组并构建嵌套JSON结构?
解决SQL Server结果集重复数据转嵌套JSON的LINQ实现方案
我之前处理过类似的报表场景,完全懂你遇到的痛点——存储过程返回的扁平化结果因为订单多商品导致重复,要转成CustomerReport -> SaleOrder -> SalesOrderItem的嵌套结构还得保留ReportSequence的显示顺序对吧?
先理清楚核心问题:原始结果集里,同一个订单的每一条数据对应一个商品,所以我们需要先按客户聚合,再在客户下按订单聚合商品,同时要确保整个层级的顺序和ReportSequence一致。
步骤1:定义扁平数据的临时实体
首先,假设从存储过程拿到的原始数据是一个IEnumerable<FlatReportRecord>集合,这个实体包含所有返回字段(包括客户、订单、商品的属性,以及ReportSequence):
public class FlatReportRecord { // 客户字段 public int CustomerId { get; set; } public string CustomerName { get; set; } // 订单字段 public int SalesOrderId { get; set; } public DateTime OrderDate { get; set; } // 商品字段 public int ItemId { get; set; } public string ItemName { get; set; } public decimal ItemPrice { get; set; } // 报表排序字段 public int ReportSequence { get; set; } }
步骤2:用LINQ实现嵌套转换
这里的关键是先按客户分组,再在每个客户组内按订单分组,同时利用ReportSequence保证排序(因为原始数据的顺序是报表要显示的顺序,所以分组前先排序更稳妥):
// 假设flatReportData是从存储过程获取的原始结果集 var nestedReport = flatReportData // 先按ReportSequence排序,确保后续分组不打乱报表显示顺序 .OrderBy(r => r.ReportSequence) // 第一步:按客户维度分组(用CustomerId作为分组键,确保同一个客户的所有订单归在一起) .GroupBy(r => new { r.CustomerId, r.CustomerName }) .Select(customerGroup => new CustomerReport { CustomerId = customerGroup.Key.CustomerId, CustomerName = customerGroup.Key.CustomerName, // 第二步:在客户组内,按订单维度分组 SaleOrders = customerGroup .GroupBy(orderItem => new { orderItem.SalesOrderId, orderItem.OrderDate }) .Select(orderGroup => new SaleOrder { SalesOrderId = orderGroup.Key.SalesOrderId, OrderDate = orderGroup.Key.OrderDate, // 收集当前订单下的所有商品 SalesOrderItems = orderGroup .Select(item => new SalesOrderItem { ItemId = item.ItemId, ItemName = item.ItemName, ItemPrice = item.ItemPrice }) .ToList() }) .ToList() }) .ToList();
为什么之前按SalesOrderId分组会失败?
大概率是因为你跳过了客户层级的分组,直接按订单分组会导致不同客户的同ID订单(虽然实际业务中不太可能,但逻辑上会出问题)被合并,或者没有先按ReportSequence排序,导致最终嵌套结构的顺序不符合报表要求。
最后转成JSON
用Newtonsoft.Json或者System.Text.Json序列化即可:
// Newtonsoft.Json示例 string jsonResult = JsonConvert.SerializeObject(nestedReport, Formatting.Indented); // System.Text.Json示例 string jsonResult = JsonSerializer.Serialize(nestedReport, new JsonSerializerOptions { WriteIndented = true });
这个方案既解决了重复数据的聚合问题,又严格保留了ReportSequence定义的报表显示顺序,完全适配你的嵌套实体结构。
内容的提问来源于stack exchange,提问作者t3zr149FA
相关产品推荐
相关产品推荐

