DataTable合并异常:并发场景下合并后出现重复主键行求助
多用户环境下DataTable合并重复主键问题的解决
问题背景
在多用户应用中处理并发异常时,出现DataTable合并的意外行为:
- 表单初始化时,通过SqlDataAdapter将Employees表数据填充到
Tbl - 修改表单上某员工FirstName后,该员工的FirstName被其他用户在数据库中修改,关闭表单更新
Tbl时触发并发异常 - 从数据库获取该员工最新值填充到
TmpTbl,调用Tbl.Merge(TmpTbl, True)期望覆盖更新Tbl对应记录,但合并后Tbl出现两条主键相同的记录
用户代码如下:
'Populate the data displayed on the form. CN.ConnectionString = ConnStr() DA.SelectCommand = New SqlCommand("Select ID, LastName, FirstName, MidInit From Employees Where Deleted Is Null And TermDate Is Null Order By " & "LastName, FirstName, MidInit", CN) DA.Fill(Tbl) 'Get values currently in the underlying database. Dim TmpTbl As New DataTable Dim DAA As New SqlDataAdapter DAA.SelectCommand = New SqlCommand("Select ID, LastName, FirstName, MidInit From Employees Where ID = " & DBCX.Row.Item("ID"), CN) DAA.Fill(TmpTbl) 'Merge the two tables. Tbl.Merge(TmpTbl, True)
问题原因
当Tbl中目标记录处于DataRowState.Modified状态(即表单修改后未提交)时,Merge方法会保留原修改行,同时将TmpTbl中的新记录作为"新行"添加——因为Merge默认会区分行的状态和版本,不会直接覆盖处于修改状态的行,最终导致主键重复。
解决办法
方法1:重置目标行状态后合并
先将Tbl中对应记录的行状态重置为Unchanged,再执行Merge,这样Merge会用TmpTbl的最新值覆盖该行:
' 定位Tbl中需要更新的目标行 Dim targetRow As DataRow = Tbl.Rows.Find(DBCX.Row.Item("ID")) If targetRow IsNot Nothing Then ' 重置行状态为Unchanged,放弃表单端的未提交修改 targetRow.AcceptChanges() End If ' 执行合并操作 Tbl.Merge(TmpTbl, True)
方法2:手动更新目标行字段
直接用TmpTbl的字段值覆盖Tbl对应行,避免Merge的状态判断逻辑影响:
If TmpTbl.Rows.Count > 0 Then Dim sourceRow As DataRow = TmpTbl.Rows(0) Dim targetRow As DataRow = Tbl.Rows.Find(sourceRow("ID")) If targetRow IsNot Nothing Then ' 逐个更新字段值 targetRow("LastName") = sourceRow("LastName") targetRow("FirstName") = sourceRow("FirstName") targetRow("MidInit") = sourceRow("MidInit") ' 若需标记为已提交,可调用AcceptChanges() ' targetRow.AcceptChanges() End If End If
方法3:确认主键设置正确性
确保Tbl和TmpTbl都正确设置主键列,避免Merge无法匹配同主键记录:
' 为Tbl设置主键 Tbl.PrimaryKey = New DataColumn() {Tbl.Columns("ID")} ' 为TmpTbl设置主键 TmpTbl.PrimaryKey = New DataColumn() {TmpTbl.Columns("ID")}
内容的提问来源于stack exchange,提问作者Larry Stinson
相关产品推荐
相关产品推荐

