使用 Dataadapter 更新时发生 DBConcurrency 异常
Posted
技术标签:
【中文标题】使用 Dataadapter 更新时发生 DBConcurrency 异常【英文标题】:DBConcurrency Exception Occured While Updating Using Dataadapter 【发布时间】:2015-12-06 13:03:12 【问题描述】:我正在尝试编辑由NpgsqlDataAdapter
填充的DataTable
。
调用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 的列 代码 有问题。当我省略它时,它就起作用了。列代码的数据类型是 varchar。 我不知道为什么会这样。有人知道吗?
【问题讨论】:
能否请您发布表 stocktable 的确切架构(您可以通过在 psql 中运行 '\d stocktable' 来做到这一点)?另外,变量 qty 的类型是什么?请注意,PG 表中只能有一个主键,而不是三个(尽管您可以拥有任意数量的索引) 另一件有帮助的事情是您正在查询的结果(即确切值) 【参考方案1】:这是因为DataAdapter
默认使用Optimistic Concurrency
。这意味着如果您尝试更新数据库中不再存在或已更改的行,则来自DataAdapter
的更新将失败,并出现上述异常。
可能的场景:
在您选择数据到客户端和发送 更新,另一个用户正在从他的应用程序中删除或更新这一行。 可能是您正在从应用程序的其他位置删除数据。例如:
-
您填写将用于更新的
DataTable
。
直接从数据库中删除带有Code = 1101
的行(例如),即您不要在此处使用DataTable
。这是模拟另一个用户从另一个应用程序中删除带有Code = 1101
的行。或代码中的其他部分删除带有Code = 1101
的行。
从DataTable
中选择带有Code = 1101
的行,这只是为了表明即使您已将其从数据库本身中删除,它仍然存在。
在DataTable
中使用Code = 1101
编辑行中的Quantity
列。必须这样做,否则更新时调用 Update 将忽略此行。
执行更新,这将引发异常,因为您正在尝试更新(不再)存在于数据库中的行。
如果要实现Last Writer Wins
,添加如下代码:
cb.ConflictOption = ConflictOption.OverwriteChanges;
还有另外一件可能的事情:如果您在数据库中有Decimal
/numeric
作为列,即使数据看起来相同,它们也可能导致此错误。这是由于小数舍入错误造成的。
重要提示:
顺便说一句,您应该始终使用parameterized queries
。这种字符串连接对SQL Injection
开放。
【讨论】:
以上是关于使用 Dataadapter 更新时发生 DBConcurrency 异常的主要内容,如果未能解决你的问题,请参考以下文章
为啥 DataAdapter.Update() 不更新数据库
在不使用 DataAdapter.Fill 的情况下更新数据表 2 次