Entity Framework按名称分组求助:现有代码分组无效
问题:Entity Framework按零件名称分组失效,重复名称无法合并
我有一段基于Entity Framework的代码,想要实现按零件名称分组统计金额的功能,但自行尝试使用GroupBy后并未生效,仍然输出重复的名称,无法实现正确分组,请求帮助修正。以下是我的原代码:
// <date,<partid,amount>> Dictionary<string, Dictionary<int, double>> emSpending = new Dictionary<string, Dictionary<int, double>>(); foreach (Orders order in db.Orders.ToList()) { foreach (OrderItems orderitem in order.OrderItems.ToList()) { if (!emSpending.ContainsKey(order.Date.ToString("yyyy-MM"))) emSpending.Add(order.Date.ToString("yyyy-MM"), new Dictionary<int, double>()); if (!emSpending[order.Date.ToString("yyyy-MM")].ContainsKey(Convert.ToInt32(orderitem.PartID))) emSpending[order.Date.ToString("yyyy-MM")].Add(Convert.ToInt32(orderitem.PartID), 0); emSpending[order.Date.ToString("yyyy-MM")][Convert.ToInt32(orderitem.PartID)] += Convert.ToDouble(orderitem.Amount); } } DataGridViewColumn col1 = new DataGridViewColumn(); col1.CellTemplate = new DataGridViewTextBoxCell(); col1.Name = "Department"; col1.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; col1.HeaderText = "Department"; dgvEMSpending.Columns.Add(col1); foreach (string date in emSpending.Keys) { DataGridViewColumn col = new DataGridViewColumn(); col.Name = date; col.HeaderText = date; col.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; col.CellTemplate = new DataGridViewTextBoxCell(); dgvEMSpending.Columns.Add(col); } List<string> allKey = emSpending.Keys.ToList(); foreach (string date in allKey) if (date == "Department") continue; else { dgvEMSpending.Rows.Add(); foreach (int partid in emSpending[date].Keys) { // 这里的GroupBy用法完全错误,单个字符串无法调用GroupBy dgvEMSpending.Rows[dgvEMSpending.Rows.Count - 1].Cells[0].Value = db.Parts.Where(x => x.ID == partid).SingleOrDefault().Name.GroupBy(Name); for (int i = 1; i < dgvEMSpending.Columns.Count; i++) { if (!emSpending.ContainsKey(dgvEMSpending.Columns[i].Name)) emSpending.Add(dgvEMSpending.Columns[i].Name, new Dictionary<int, double>()); if (!emSpending[dgvEMSpending.Columns[i].Name].ContainsKey(partid)) emSpending[dgvEMSpending.Columns[i].Name].Add(partid, 0); double val = emSpending[dgvEMSpending.Columns[i].Name][partid]; dgvEMSpending.Rows[dgvEMSpending.RowCount - 1].Cells[i].Value = val; } } }
问题分析
- 原代码的统计逻辑是按
PartID分组,而非零件名称,后续试图在填充单元格时用GroupBy完全错误——GroupBy是对集合的操作,单个字符串无法调用该方法。 - 循环中反复查询
db.Parts获取名称,不仅效率低,也没有从根源上按名称合并金额。 - 填充DataGridView时的逻辑混乱,导致同一名称多次出现。
修正后的代码
// 预加载零件ID与名称的映射,避免循环中反复查询数据库 var partNameMap = db.Parts.ToDictionary(p => p.ID, p => p.Name); // 重新构建统计结构:按日期->零件名称->总金额分组 Dictionary<string, Dictionary<string, double>> emSpendingByName = new Dictionary<string, Dictionary<string, double>>(); foreach (var order in db.Orders) { string dateKey = order.Date.ToString("yyyy-MM"); foreach (var item in order.OrderItems) { // 跳过不存在的零件记录 if (!partNameMap.TryGetValue(item.PartID, out string partName)) continue; // 初始化日期分组 if (!emSpendingByName.ContainsKey(dateKey)) emSpendingByName[dateKey] = new Dictionary<string, double>(); // 初始化该日期下的零件金额 if (!emSpendingByName[dateKey].ContainsKey(partName)) emSpendingByName[dateKey][partName] = 0; // 累加金额 emSpendingByName[dateKey][partName] += Convert.ToDouble(item.Amount); } } // 清空DataGridView原有内容 dgvEMSpending.Columns.Clear(); dgvEMSpending.Rows.Clear(); // 添加零件名称列 DataGridViewColumn nameColumn = new DataGridViewColumn { CellTemplate = new DataGridViewTextBoxCell(), Name = "Department", AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill, HeaderText = "零件名称" }; dgvEMSpending.Columns.Add(nameColumn); // 添加日期列 foreach (string date in emSpendingByName.Keys) { DataGridViewColumn dateColumn = new DataGridViewColumn { Name = date, HeaderText = date, AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill, CellTemplate = new DataGridViewTextBoxCell() }; dgvEMSpending.Columns.Add(dateColumn); } // 获取所有唯一的零件名称,确保每个名称只出现一行 var allUniquePartNames = emSpendingByName.Values .SelectMany(dateDict => dateDict.Keys) .Distinct() .ToList(); // 填充每行数据 foreach (string partName in allUniquePartNames) { int rowIndex = dgvEMSpending.Rows.Add(); dgvEMSpending.Rows[rowIndex].Cells["Department"].Value = partName; foreach (DataGridViewColumn column in dgvEMSpending.Columns) { if (column.Name == "Department") continue; // 读取对应日期下的零件金额,无数据则填0 if (emSpendingByName.TryGetValue(column.Name, out var dateAmounts) && dateAmounts.TryGetValue(partName, out double totalAmount)) { dgvEMSpending.Rows[rowIndex].Cells[column.Index].Value = totalAmount; } else { dgvEMSpending.Rows[rowIndex].Cells[column.Index].Value = 0; } } }
修正说明
- 从根源分组:直接按零件名称统计金额,而非先按PartID统计再处理名称,确保同一名称的金额自动合并。
- 减少数据库查询:预加载零件ID与名称的映射字典,避免循环中反复查询数据库,提升效率。
- 正确填充表格:先收集所有唯一的零件名称,再逐个填充行,确保每个名称只出现一次。
- 修复GroupBy错误:移除原代码中无效的GroupBy调用,改用字典分组的方式实现需求。
内容的提问来源于stack exchange,提问作者pokelawls
相关产品推荐
相关产品推荐

