C#基于EF编写LINQ实现分类供应商动态列分组透视统计
EF Core 动态透视表实现(输出可直接绑定DataTable)
实体映射(对应三张业务表)
首先确认EF实体映射和表结构匹配,核心实体定义如下:
public class Vendor { public int VendorId { get; set; } public string VendorName { get; set; } } public class Category { public int CategoryId { get; set; } public string CategoryName { get; set; } } public class Product { public int ProductId { get; set; } public int VendorId { get; set; } public int CategoryId { get; set; } // 导航属性,提前配置好EF关联映射 public Vendor Vendor { get; set; } public Category Category { get; set; } }
实现逻辑
- 聚合逻辑下推到数据库执行:三表关联+分组计数的操作全部生成SQL执行,只返回聚合后的轻量结果,避免加载全量商品明细到内存
- 动态列自动生成:从聚合结果中提取全量不重复供应商作为列,后续新增供应商无需修改代码会自动生成对应列
- 动态构建DataTable:固定分类维度列+动态供应商列+总计列,逐行填充计数结果,最终输出的DataTable可直接绑定到数据控件
完整代码
public async Task<DataTable> GetProductPivotTableAsync() { using var db = new YourAppDbContext(); // 数据库侧执行聚合,返回分类-供应商维度的商品计数 var aggResult = await ( from p in db.Products join c in db.Categories on p.CategoryId equals c.CategoryId join v in db.Vendors on p.VendorId equals v.VendorId group p by new { c.CategoryId, c.CategoryName, v.VendorId, v.VendorName } into g select new { g.Key.CategoryId, g.Key.CategoryName, g.Key.VendorId, g.Key.VendorName, Count = g.Count() } ).AsNoTracking().ToListAsync(); // 提取所有供应商作为动态列,可按需调整排序规则 var vendorColumns = aggResult .Select(x => new { x.VendorId, x.VendorName }) .Distinct() .OrderBy(v => v.VendorName) .ToList(); // 初始化DataTable结构 var pivotTable = new DataTable(); pivotTable.Columns.Add("CategoryId", typeof(int)); pivotTable.Columns.Add("分类名称", typeof(string)); foreach (var vendor in vendorColumns) { pivotTable.Columns.Add(vendor.VendorName, typeof(int)); } pivotTable.Columns.Add("总计", typeof(int)); // 按分类分组填充行数据 foreach (var catGroup in aggResult.GroupBy(x => new { x.CategoryId, x.CategoryName })) { var row = pivotTable.NewRow(); row["CategoryId"] = catGroup.Key.CategoryId; row["分类名称"] = catGroup.Key.CategoryName; int totalCount = 0; foreach (var vendor in vendorColumns) { var currentCount = catGroup.FirstOrDefault(x => x.VendorId == vendor.VendorId)?.Count ?? 0; row[vendor.VendorName] = currentCount; totalCount += currentCount; } row["总计"] = totalCount; pivotTable.Rows.Add(row); } return pivotTable; }
优化说明
- 加了
AsNoTracking取消变更追踪,进一步提升查询性能 - 供应商对应计数为空时默认填0,避免出现DBNull导致绑定控件报错
- 如果需要过滤无效供应商、已下架分类,直接在聚合查询部分加
Where条件即可,后续逻辑无需调整
内容的提问来源于stack exchange,提问作者Shubhit304
相关产品推荐
相关产品推荐

