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



我有一个.net winforms应用程序,它正在使用SQLite DB,而我正在使用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.DBConcurrentException"的未经处理的异常附加信息:并发冲突: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;

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

可悲的事实是:这不是SQLite或ADO.NET中的错误。DbAdapter和DbCommandBuilder期望强类型,而SQLite在设计上并没有提供强类型。

我见过这个问题,它似乎出现在某些情况下,而不是其他情况。我用不同的方式解决了这个问题。由于这主要是一个数据问题,因此需要更改更新和删除语句。在某些情况下,您的代码可能需要验证,我不是指那些情况,这是针对其他一切似乎都正常并且"并发冲突"持续存在的情况。在花数小时调试之前,一个好的起点是解决如何处理更新。

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

编辑SQL,使Where子句只引用主键。

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

更新。。。。。WHERE EmployeeID=@Employe_ID

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

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

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

但是,这是开发和数据库团队需要协调的更新/删除策略决定。对于一个单独的开发人员/dba来说,与自己开一个小会。未经您的审查、理解和明确实施,请勿使用Microsoft where子句。需要从应用程序和数据库级别具体说明当两个用户拥有同一记录的副本时会发生什么。SQL Server中的数据库"事务隔离"级别是解决此问题的一种方法。ADO、ADO.NET、OLE DB、ODBC都有隔离级别设置。有关SQL Server事务和隔离级别的更多信息

在某些情况下,不涉及多个用户,或者应用程序正在内部更新,并发性是完全受控的,其中子句可以用主键形成。

在我的情况下,更新是在没有用户参与的情况下完成的,因此使用主键是有意义的。如果你了解这种行为的原因和原因,那就需要调整以适应你的环境。

最新更新