使用 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.Update() 不更新数据库

在不使用 DataAdapter.Fill 的情况下更新数据表 2 次

如何使用 DataAdapter.Update 方法同时更新 Access 数据库和 .NET DataSet 对象?

为啥 DataAdapter.Update 啥也不更新?

DataAdapter Update 方法批量更新多行