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

C#对比两个DataGridView单元格值仅插入差异行问题排查

问题背景

项目中使用2个DataGridView控件,分别为承载新结果数据的dgvResult、承载旧结果数据的dgvresultold,业务需求为:仅当dgvResult某行第3列(索引为3)的单元格值,与dgvresultold同索引行第3列的单元格值不相等时,才将dgvResult对应行的数据插入数据库。

初始版本代码运行时存在问题:点击保存按钮后所有行都会被存入数据库,不符合仅插入差异行的要求;调整对比逻辑后又出现完全无法插入数据的故障。

现有代码片段

保存按钮初始版本代码

private void btnSave_Click(object sender, EventArgs e)
{
    for (int i = 0; i < dgvResult.Rows.Count; i++)
    {
        if (!String.IsNullOrEmpty(dgvResult.Rows[i].Cells[3].Value.ToString()))
        {
            if (dgvResult.Rows[i].Cells[3].Value.ToString() != dgvresultold.Rows[i].Cells[3].Value.ToString())
            {
                result.UPDATED_RESULTS(Convert.ToInt32(txtOrder.Text),
                                  Convert.ToInt32(dgvResult.Rows[i].Cells[0].Value),
                                         txtApprovedby.Text,
                                 DateTime.Parse(dateTimeApprove.Value.ToString()),
                                 dgvResult.Rows[i].Cells[3].Value.ToString(),
                                 
                                Convert.ToInt32(dgvResult.Rows[i].Cells[4].Value.ToString()),
                                 Convert.ToInt32(txtMRN.Text),
                                 Convert.ToInt32(textCustId.Text),
                                 txtApprovedby.Text,
                                 DateTime.Parse(dateTimeApprove.Value.ToString()), 1,
                                 Convert.ToInt32(dgvResult.Rows[i].Cells[7].Value),
                                 dgvResult.Rows[i].Cells[8].Value.ToString());
              }
    }
}

初始版本使用的值对比逻辑如下,预期仅命中值存在差异的行:

if (dgvResult.Rows[i].Cells[3].Value.ToString() != dgvresultold.Rows[i].Cells[3].Value.ToString())

数据插入存储过程代码

ALTER proc [dbo].[UPDATED_RESULTS]
@ORDER_ID int,
@TESTID int,
@APPROVED_BY varchar(50),
@APPROVED_DATE datetime, 
@RESULT_NUMBER varchar(50),
@MACHINE_ID int,
@patient_no int,
@custid int,
@CORRECTED_BY varchar(50),
@CORRECTED_DATE datetime,
@messageid int,
@deptid int,
@REQ_FORM_NO varchar(50)
AS
INSERT INTO [dbo].[LAB_RESULTS_UPDATED]
           ([TESTID],[ORDER_ID],[APPROVED_BY],[APPROVED_DATE],[RESULT_NUMBER],[machine_id],[patient_no],[custid],[CORRECTED_BY],[CORRECTED_DATE]
           ,[messageid],deptid,REQ_FORM_NO)
           values 
           (@ORDER_ID,@TESTID,@APPROVED_BY,@APPROVED_DATE,@RESULT_NUMBER,@MACHINE_ID,@patient_no,@custid,@CORRECTED_BY,@CORRECTED_DATE,
           @messageid,@deptid,@REQ_FORM_NO)

调整后失效的循环代码

调整循环边界、改用String.Equals做对比后,代码完全无法执行插入操作,对应循环片段如下:

for (int i = 0; i < dgvResult.Rows.Count-1; i++)
{
    if (!String.IsNullOrEmpty(dgvResult.Rows[i].Cells[3].Value.ToString()))
    {
        if (!String.Equals(dgvResult.Rows[i].Cells[3].Value.ToString() , dgvresultold.Rows[i].Cells[3].Value.ToString()))
        {
            result.UPDATED_RESULTS(Convert.ToInt32(txtOrder.Text),
                                  Convert.ToInt32(dgvResult.Rows[i].Cells[0].Value),
                                         txtApprovedby.Text,
                                 DateTime.Parse(dateTimeApprove.Value.ToString()),
                                 dgvResult.Rows[i].Cells[3].Value.ToString(),
                                 Convert.ToInt32(dgvResult.Rows[i].Cells[4].Value.ToString()),
                                 Convert.ToInt32(txtMRN.Text),
                                 Convert.ToInt32(textCustId.Text),
                                 txtApprovedby.Text,
                                 DateTime.Parse(dateTimeApprove.Value.ToString()), 1,
                                 Convert.ToInt32(dgvResult.Rows[i].Cells[7].Value),
                                 dgvResult.Rows[i].Cells[8].Value.ToString());
        }
    }
}
故障原因排查
  • 空值处理缺失:代码直接对单元格的Value属性调用ToString(),如果dgvresultold对应单元格值为null或DBNull,会直接抛出空引用异常,中断整个保存流程,这是调整后完全无法插入数据的核心原因。
  • 新行处理逻辑错误:DataGridView默认开启AllowUserToAddRows属性时,会在列表末尾自动生成一行空白的用户编辑行,硬编码Rows.Count-1虽然能跳过这行,但如果后续关闭该属性,会导致最后一行有效数据被漏处理;初始版本没有跳过这行时,空白行的空值和旧表值对比必然不等,会触发无意义插入。
  • 值对比未做归一化:如果单元格值首尾存在不可见空格、存储格式不一致(比如数值转字符串后小数位不同、大小写差异),会导致视觉上相等的值被判定为不等,触发全量插入。
  • 缺少行数一致性校验:如果两个DataGridView加载的有效数据行数不一致,按同索引对比会出现索引越界、行数据匹配错误的问题。
修复后的完整实现代码
private void btnSave_Click(object sender, EventArgs e)
{
    // 动态计算两个表的有效数据行数,自动跳过末尾的用户新增空白行
    int newValidRowCount = dgvResult.Rows.Count - (dgvResult.AllowUserToAddRows ? 1 : 0);
    int oldValidRowCount = dgvresultold.Rows.Count - (dgvresultold.AllowUserToAddRows ? 1 : 0);
    
    // 行数不匹配时直接终止流程,避免索引越界
    if (newValidRowCount != oldValidRowCount)
    {
        MessageBox.Show("新旧结果数据行数不匹配,无法执行保存操作");
        return;
    }

    for (int i = 0; i < newValidRowCount; i++)
    {
        // 安全获取新值,统一处理null/DBNull情况,同时去除首尾空格做归一化
        string newResult = dgvResult.Rows[i].Cells[3].Value?.ToString().Trim() ?? string.Empty;
        // 新值为空则跳过当前行
        if (string.IsNullOrEmpty(newResult)) continue;

        // 安全获取旧值
        string oldResult = dgvresultold.Rows[i].Cells[3].Value?.ToString().Trim() ?? string.Empty;

        // 仅当新旧值不相等时执行插入,可根据业务需要调整是否忽略大小写
        if (!string.Equals(newResult, oldResult, StringComparison.Ordinal))
        {
            result.UPDATED_RESULTS(
                orderId: Convert.ToInt32(txtOrder.Text),
                testId: Convert.ToInt32(dgvResult.Rows[i].Cells[0].Value),
                approvedBy: txtApprovedby.Text,
                approveDate: DateTime.Parse(dateTimeApprove.Value.ToString()),
                resultNumber: newResult,
                machineId: Convert.ToInt32(dgvResult.Rows[i].Cells[4].Value.ToString()),
                patientNo: Convert.ToInt32(txtMRN.Text),
                custId: Convert.ToInt32(textCustId.Text),
                correctedBy: txtApprovedby.Text,
                correctedDate: DateTime.Parse(dateTimeApprove.Value.ToString()),
                messageId: 1,
                deptId: Convert.ToInt32(dgvResult.Rows[i].Cells[7].Value),
                reqFormNo: dgvResult.Rows[i].Cells[8].Value.ToString()
            );
        }
    }
}

修复点说明

  • 采用空值传播运算符?.和空值合并运算符??处理单元格取值,彻底避免空引用异常
  • 动态计算有效行数,兼容AllowUserToAddRows属性开关的两种场景,不会漏处理数据也不会读取空白新增行
  • 对比前对字符串做Trim处理,消除首尾空格导致的对比误判,可根据业务需要调整字符串对比规则
  • 增加前置行数校验,从根源上避免索引越界问题

内容的提问来源于stack exchange,提问作者MarwanAbu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.01 15:51:38