You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
            }
        }
    }

问题分析

  1. 原代码的统计逻辑是按PartID分组,而非零件名称,后续试图在填充单元格时用GroupBy完全错误——GroupBy是对集合的操作,单个字符串无法调用该方法。
  2. 循环中反复查询db.Parts获取名称,不仅效率低,也没有从根源上按名称合并金额。
  3. 填充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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 16:56:04