C# System.Data.SQLite:并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条

Posted

技术标签:

【中文标题】C# System.Data.SQLite:并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条【英文标题】:C# System.Data.SQLite : Concurrency violation: the UpdateCommand affected 0 of the expected 1 records 【发布时间】:2016-05-03 05:22:10 【问题描述】:

我有一个使用 SQLite DB 的 .net winforms 应用程序,我正在使用 System.Data.SQLite dll。

这是我加载数据表的方式:

            DataTable table = new DataTable();
            SQLiteDataAdapter m_readingsDataTableDataAdapter;
            SQLiteCommandBuilder m_readingsDataTableCommandBuilder;

            m_readingsDataTableCommandBuilder = null;
            m_readingsDataTableDataAdapter = null;

            // Create fresh objects
            m_readingsDataTableDataAdapter = new SQLiteDataAdapter(sql, Database.getInstance().connectionObj);
            m_readingsDataTableCommandBuilder = new SQLiteCommandBuilder(m_readingsDataTableDataAdapter);
            m_readingsDataTableDataAdapter.Fill(table);
            return table;             

此数据表有一个主键,没有其他约束。 我将它设置为 DataGridView 的数据源,在所有编辑之后,我像这样更新 DataTable:

    m_readingsDataTableDataAdapter.Update(table);

有时,更新会引发错误,我不知道何时会停止抛出错误 - 可能在系统重新启动后(不确定)。然后,更新正常,直到此更新再次引发错误的另一种情况。发生错误时,即使在应用程序重新启动后,从那时起的所有更新都会发生此错误。

错误: System.Data.dll 中出现“System.Data.DBConcurrencyException”类型的未处理异常 附加信息:并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条。

如果有任何帮助或问题,我将不胜感激,因为这是我项目中非常关键的部分。

谢谢。

更新:

根据建议,为确保程序没有其他部分正在编辑该行,我加载了 DataTable,立即更新了该行并按照以下代码对其进行了更新。 我仍然得到错误。我的机器上没有运行其他程序,因此除了我的应用程序之外的任何其他程序都不会更新该行:

    DataTable table = new DataTable();
            SQLiteDataAdapter m_readingsDataTableDataAdapter;
            SQLiteCommandBuilder m_readingsDataTableCommandBuilder;

            m_readingsDataTableCommandBuilder = null;
            m_readingsDataTableDataAdapter = null;

            // Create fresh objects
            m_readingsDataTableDataAdapter = new SQLiteDataAdapter(sql, Database.getInstance().connectionObj);
            m_readingsDataTableCommandBuilder = new SQLiteCommandBuilder(m_readingsDataTableDataAdapter);
            m_readingsDataTableDataAdapter.Fill(table);

            // Update immediately
            table.Rows[0]["RS485_ADDRESS"] = "400";
            m_readingsDataTableDataAdapter.Update(table); // - Still throws error

            return table;

【问题讨论】:

这意味着数据适配器和命令预期存在的行不再存在,或者它存在但它具有一些不同的关键值。货币违规源于这样一个事实,即当数据适配器最初检索数据时,它会制作两份副本,一份是底层副本,一份是公共副本。当您稍后尝试将更新保存回数据库时,它首先尝试验证该行是否仍在数据库中,并具有与最初相同的值。如果是,然后它执行更新。很明显,该行不存在或已更改。 意味着当您在一个地方操作该行时,其他一些代码或其他一些程序正在同时更新数据库中的同一行。当您稍后尝试更新它时,更新命令基本上说“将数据库中最初余额为 45 且最后到期日为今天的这一行更新为这个新余额”,并且该行在那里,但它不再余额为 45。 除了解释之外,我们无法帮助您,因为这需要您查看程序的大部分内容才能找出行意外更改的原因。如果您确实希望该行按照上述说明进行更改,那么您不能使用这种更新表的系统,因为这导致问题。 非常感谢 Lasse 提供的信息丰富的回复。这真的很有帮助。我将对此进行进一步调查。 我对此进行了调查,根据我们拥有的代码,我确信该程序不会从其他“任何地方”更新“任何”行。实际上,我加载了一个表,连续更改了一个值并立即更新。它仍然抛出异常。请同时查看我的更新问题以及此信息和代码。 【参考方案1】:

我遇到了一个类似的问题,几乎让我发疯。我什至调试到 System.Data.SQLite 。我的问题是由 SQLite 的动态类型引起的: 动态类型意味着列类型只是存储值类型的提示,而不是强制执行。这是我的应用程序中发生的情况:一个整数列包含一个空字符串。获取数据触发了到列类型的隐式转换,因此空字符串被转换为零。 DbDataAdapter 在 UPDATE 或 DELETE 语句的 WHERE 子句中使用了这个零值,由于零到字符串的转换不是空字符串,该语句惨遭失败。我将受影响的整数列更改为包含 NULL,现在一切正常。

关于这一点的可悲事实:这不是 SQLite 或 ADO.NET 中的错误。 DbAdapter 和 DbCommandBuilder 期望强类型化,而 SQLite 并没有通过设计来提供。

【讨论】:

我遇到了完全相同的问题。你拯救了我的一天(也许更多!)【参考方案2】:

我已经看到了这个问题,它似乎出现在某些情况下而不是其他情况下。我以不同的方式解决了它。由于这主要是一个数据问题,它涉及更改更新和删除语句。可能存在您的代码可能需要验证的情况,我不是指这些情况,这是因为当一切似乎都正常并且“并发冲突”仍然存在时。在花费数小时进行调试之前,一个很好的起点是解决更新的处理方式。

打开数据集设计器。 单击表适配器。 在属性中,展开 UpdateCommand

编辑 SQL,使 Where-Clause 仅引用主键。

示例:假设 EmployeeID 列是我们表中的主键 改为:

更新..... WHERE EmployeeID=@EmployeeID

默认情况下,它通常构造为:

更新 ... 其中 ID=@ID AND col1=@col1 AND col2=@col2 AND col3=@col3

where 子句由处理多用户更新的所有列组成,以强制执行隐式并发。因此,如果一个用户拥有记录的副本,而另一个用户在第一个用户更新它时更新了该版本,则第一个用户的版本不是最新的。否则,应使用主键来引用特定记录。

但是,这是开发和数据库团队需要协调的更新/删除策略决策。对于单一的开发人员/dba in-one,与自己进行一次小型会议。未经您的审查、理解和明确实施,请勿使用 Microsoft where 子句。需要特别解决当 2 个用户从应用程序和数据库级别拥有相同记录的副本时会发生什么。 SQL Server 中的数据库“事务隔离”级别是一种解决方法。 ADO、ADO.NET、OLE DB、ODBC 都有隔离级别设置。 More on SQL Server Transactions and isolation levels

在某些情况下不涉及多个用户,或者应用程序正在内部更新,并发性是完全控制的,可以使用主键形成 where-clause。

在我的例子中,更新是在没有用户参与的情况下完成的,所以使用主键是有意义的。如果您了解行为的原因和原因,则需要进行调整以适应您的环境。

【讨论】:

以上是关于C# System.Data.SQLite:并发冲突:UpdateCommand 影响了预期的 1 条记录中的 0 条的主要内容,如果未能解决你的问题,请参考以下文章

使用 System.Data.SQLite (C#) 的 SQLite 查询比在 SQLiteStudio 中要慢得多

C# 引入Sqlite 未能加载文件或程序集“System.Data.SQLite

C#里System.Data.SQLite中对GUID的处理

C#操作Sqlite快速入门及相关工具收集

[C#][转载]Sqlite操作大全

System.Data.Sqlite 1.0.99 引导比较不起作用