使用Dataadapter更新时发生DBConcurrencyexception

我正在尝试编辑由NpgsqlDataAdapter填充的NpgsqlDataAdapter 。 在调用Fill()方法之后,我在DataTable只有一行。 然后我只更改了一列的值,并尝试更新如下。

在此处输入图像描述

然后我收到这个错误:

发生了DBConcurrencyException

我的代码是:

 NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT sn, code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "' ORDER BY EDate ASC", DatabaseConnectionpg); DataTable ds1 = new DataTable(); ds1.Clear(); getAllData.Fill(ds1); if (ds1.Rows.Count > 0) { ds1.Rows[0]["Quantity"] = qty;// calculated value } ds1 = ds1.GetChanges(); NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(getAllData); //getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); }; //cb.SetAllValues = false; getAllData.DeleteCommand = cb.GetDeleteCommand(); getAllData.InsertCommand = cb.GetInsertCommand(); getAllData.UpdateCommand = cb.GetUpdateCommand(); int x = getAllData.Update(ds1); if (x > 0) { ds1.AcceptChanges(); } 

编辑:我有三个字段作为主键,我只在select语句中调用两个字段。 DBConcurrency出错的原因是什么? 但我能够在SQL Server 2005中使用相同的(三个字段作为主键)参数更新表。

更新:

我找到了解决方案,解决方案是我创建并使用第二个DataAdapter来更新数据。 我使用了getAllData (NpgSqlDataAdapter)将表填充为

 NpgsqlDataAdapter getAllData = new NpgsqlDataAdapter("SELECT code,product, unitprice, quantity, InvoiceNo, Date FROM stocktable WHERE Code='" + product + "' ORDER BY EDate ASC", DatabaseConnectionpg); 

并创建了下一个适配器以更新为

 NpgsqlDataAdapter updateadap= new NpgsqlDataAdapter("SELECT sn, quantity FROM stocktable WHERE Code='" + product + "' ORDER BY EDate ASC", DatabaseConnectionpg); NpgsqlCommandBuilder cb = new NpgsqlCommandBuilder(updateadap); //getAllData.RowUpdating += (sender2, e2) => { e2.Command.Parameters.Clear(); }; //cb.SetAllValues = false; updateadap.DeleteCommand = cb.GetDeleteCommand(); updateadap.InsertCommand = cb.GetInsertCommand(); updateadap.UpdateCommand = cb.GetUpdateCommand(); int x = updateadap.Update(ds1); if (x > 0) { ...... } 

我尝试了很多,发现NpgsqlDataAdapter有列代码问题。 当我忽略它然后它工作。 列代码的DataType是varchar。 我不知道为什么会这样。 有人有想法吗?

这是因为DataAdapter默认使用Optimistic Concurrency 。 这意味着,如果您尝试更新数据库中不再存在的行或已更改,则DataAdapter的更新将失败,并带有上述exception。

可能的情况

  • 在您将数据选择到客户端并发送更新之间,另一个用户正在从他的应用程序中删除或更新此行。
  • 可能是您正在从应用程序中的其他位置删除数据。

例如

  1. 您填写将用于更新的DataTable
  2. 直接从数据库中删除Code = 1101 (例如)的行,即您不在此处使用DataTable 。 这是模拟另一个用户从另一个应用程序中删除Code = 1101的行。 或者代码中的其他部分删除Code = 1101的行。
  3. DataTable选择Code = 1101的行,这只是为了表明它仍然存在,即使您已从数据库本身删除它。
  4. 使用DataTable中的Code = 1101编辑行中的Quantity列。 必须这样做,否则对Update的调用将在更新时忽略此行。
  5. 执行更新,这将抛出exception,因为您尝试更新数据库中(不再存在)的行。

如果要实现Last Writer Wins ,请添加以下代码:

 cb.ConflictOption = ConflictOption.OverwriteChanges; 

还有一个可能的事情:如果在数据库中有Decimal / numeric作为列,即使数据看起来相同,它们也可能导致此错误。 这是由于十进制舍入误差造成的。

一个重要的注意事项 :您应该始终使用parameterized queries 。 这种字符串连接对SQL Injection是开放的。