如何用LINQ按日期分组生成含客户与嵌套记录的报表行列表?
按日期、客户分组生成报表的实现方案
核心思路
通过LINQ对Record列表进行两次分组:先按ImportTimestamp的日期部分分组,再在每个日期组内按Customer分组,最终映射到ReportRow列表供视图渲染。
步骤1:优化数据查询(避免N+1问题)
首先确保从数据库查询时提前加载Customer关联数据,避免Entity Framework延迟加载导致的性能问题:
// 替换原Db.GetRecords方法,确保包含Customer关联 IEnumerable<Record> Records = Db.Records .Where(r => r.ImportTimestamp >= StartDate && r.ImportTimestamp <= EndDate) .Include(r => r.Customer) // 预加载Customer,避免N+1查询 .ToList();
步骤2:分组生成ReportRow列表
使用LINQ分组并转换为视图模型需要的结构:
// 生成报表行数据 var reportRows = Records // 第一层:按日期分组(忽略时间部分) .GroupBy(r => r.ImportTimestamp.Date) .Select(dateGroup => new ReportRow { ImportDate = dateGroup.Key, // 第二层:在当前日期组内按Customer分组 Customers = dateGroup .GroupBy(r => r.Customer) .Select(customerGroup => { // 给Customer的Records属性赋值当前组的记录 customerGroup.Key.Records = customerGroup.ToList(); return customerGroup.Key; }) .OrderBy(c => c.Name) // 可选:按客户名称排序 }) .OrderBy(row => row.ImportDate) // 按日期升序排列 .ToList(); // 赋值到视图模型 ViewModel.Rows = reportRows;
步骤3:视图层渲染示例(以Razor为例)
遍历ReportRow列表,按预期格式展示:
@foreach (var row in Model.Rows) { <h3>@row.ImportDate.ToString("dd/MM/yyyy")</h3> <ul> @foreach (var customer in row.Customers) { <li>@customer.Name <ul> @foreach (var record in customer.Records) { <li>@record.OrderRef (记录ID: @record.ID)</li> } </ul> </li> } </ul> }
可选优化:使用DTO避免修改原实体
如果不想修改Customer实体的Records属性(防止影响其他业务逻辑),可以创建专门的DTO类:
// 定义客户DTO public class CustomerReportDTO { public string Name { get; set; } = default!; public IEnumerable<Record> Records { get; set; } = default!; } // 修改ReportRow的Customers类型 public class ReportRow { public DateTime ImportDate { get; set; } public IEnumerable<CustomerReportDTO> Customers { get; set; } }
然后调整分组逻辑:
Customers = dateGroup .GroupBy(r => r.Customer) .Select(customerGroup => new CustomerReportDTO { Name = customerGroup.Key.Name, Records = customerGroup.ToList() }) .OrderBy(c => c.Name)
内容的提问来源于stack exchange,提问作者user18345871
相关产品推荐
相关产品推荐

