使用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。
可能的情况 :
- 在您将数据选择到客户端并发送更新之间,另一个用户正在从他的应用程序中删除或更新此行。
- 可能是您正在从应用程序中的其他位置删除数据。
例如 :
- 您填写将用于更新的
DataTable
。 - 直接从数据库中删除
Code = 1101
(例如)的行,即您不在此处使用DataTable
。 这是模拟另一个用户从另一个应用程序中删除Code = 1101
的行。 或者代码中的其他部分删除Code = 1101
的行。 - 从
DataTable
选择Code = 1101
的行,这只是为了表明它仍然存在,即使您已从数据库本身删除它。 - 使用
DataTable
中的Code = 1101
编辑行中的Quantity
列。 必须这样做,否则对Update的调用将在更新时忽略此行。 - 执行更新,这将抛出exception,因为您尝试更新数据库中(不再存在)的行。
如果要实现Last Writer Wins
,请添加以下代码:
cb.ConflictOption = ConflictOption.OverwriteChanges;
还有一个可能的事情:如果在数据库中有Decimal
/ numeric
作为列,即使数据看起来相同,它们也可能导致此错误。 这是由于十进制舍入误差造成的。
一个重要的注意事项 :您应该始终使用parameterized queries
。 这种字符串连接对SQL Injection
是开放的。