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

WinForms Binding Source Navigator并发错误排查求助

解决WinForms BindingNavigator分页时的并发更新错误

看起来你遇到的问题虽然标注为“并发错误”,但因为你是唯一用户,本质是DataSet行状态管理和数据库行版本不一致导致的,而非真正的多用户并发。结合你的代码,我来梳理几个可能的原因和对应的解决方案:

1. 手动调用AcceptChanges()是大概率的元凶

你的updateDataItems()方法最后调用了xyzDataSet.AcceptChanges(),这会把整个DataSet里所有行的RowState强制设为Unchanged,并且将行的Original值覆盖为Current值。这会干扰TableAdapter的正常状态追踪:

  • 第一次更新CUSTOMER字段后,AcceptChanges()会把该行的Original值同步为新的CUSTOMER值,但数据库里的ACCT_NO还是旧值;
  • 当你修改ACCT_NO再次调用updateDataItems()时,TableAdapter会用当前的Original值(包括新CUSTOMER、旧ACCT_NO)去匹配数据库行,但如果你的TableAdapter并发检查逻辑是“对比所有字段”,可能因为其他隐含字段(比如最后修改时间)未同步,导致匹配失败。

修复方案:移除全局的AcceptChanges()调用,因为TableAdapter的Update()方法会自动对成功更新的行调用AcceptChanges(),不需要手动全局执行:

void updateDataItems() {
    this.procBindingSource.EndEdit();
    this.procTableAdapter.Update(xyzDataSet);
    // 删掉这行:xyzDataSet.AcceptChanges();
}

2. 手动BeginEdit/EndEdit与BindingSource的编辑状态冲突

你在代码中手动对DataRowView调用了BeginEdit()和EndEdit(),但BindingSource本身会自动管理行的编辑状态(当你修改DataRowView的字段时,它会自动进入编辑状态)。嵌套的手动编辑操作可能导致行状态混乱,进而引发更新时的版本不匹配。

修复方案:去掉不必要的手动编辑控制,简化业务代码:

// save current work 
updateDataTable(); 

// Open a window and get new customer info 
// CurrentCustomer is returned from the opened window 
using (SqlConnection cx = new SqlConnection(GetConnectionString())) {
    DataRowView dataRow = (DataRowView)procBindingSource.Current;
    // 直接修改字段,BindingSource会自动处理编辑状态
    dataRow["CUSTOMER"] = CurrentCustomer;
    updateDataItems(); 

    SqlCommand cmd = new SqlCommand(@"select acct_no from cust_processing where id = @id", cx);
    cmd.Parameters.AddWithValue("@id", (int)dataRow["ID"]);
    cx.Open();
    var results = cmd.ExecuteScalar();
    if (results != null) {
        dataRow["ACCT_NO"] = results.ToString();
        updateDataItems(); 
    }
}

3. updateDataTable()的实现可能存在数据覆盖问题

你提到updateDataTable()是为了确保使用最新版本的行,如果它的逻辑是重新从数据库填充DataSet,那必须先保存当前未提交的修改,否则新填充的数据会覆盖你之前的编辑,导致后续更新时版本不匹配。

检查并修复updateDataTable():

void updateDataTable() {
    // 先保存未提交的修改
    updateDataItems();
    // 清空旧数据再填充新数据
    xyzDataSet.proc.Clear();
    procTableAdapter.Fill(xyzDataSet.proc);
}

4. 配置TableAdapter的刷新与并发检查策略

打开你的DataSet设计器,右键点击procTableAdapter选择「配置」,进入「高级选项」:

  • 勾选「刷新数据表」:确保Update()之后,TableAdapter会自动从数据库获取最新的行数据(包括timestamp、自增字段等),同步到DataSet中;
  • 调整并发模式:如果你的表有timestamp字段,选择「仅比较时间戳」会比「比较所有值」更可靠,避免因字段过多导致的版本不匹配。

5. 验证子窗口前后的Current行是否一致

偶尔子窗口以ShowDialog()打开时,主窗体可能因失去焦点触发BindingNavigator的位置变化(比如不小心滚动了分页),导致你后续修改的不是原来的行。可以在子窗口打开前后记录procBindingSource.Position或者当前行的ID值,确认返回后没有变化。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:42:48