我有一个使用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.Data.DBConcurrencyException'的未处理异常发生在System.Data.dll中 附加信息:并发冲突: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;
答案 0 :(得分:1)
我有一个类似的问题让我差点疯了。我甚至调试了System.Data.SQLite。我的问题是由SQLite的动态类型引起的: 动态类型意味着列类型只是存储值类型的提示,而不是强制执行。以下是我的应用程序中发生的情况:整数列包含空字符串。获取数据会触发隐式转换为列类型,因此空字符串转换为零。 DbDataAdapter在UPDATE或DELETE语句的WHERE子句中使用此零值,该语句失败,因为零到字符串的转换不是空字符串。我将受影响的整数列更改为包含NULL,现在一切正常。
关于这一点的可悲事实:它不是SQLite或ADO.NET中的错误。 DbAdapter和DbCommandBuilder期望强类型,而SQLite不提供设计。
答案 1 :(得分:0)
我已经看到了这个问题,它似乎出现在某些情况下,而不是其他情况。我以不同的方式解决了它。由于这主要是数据问题,因此涉及更改更新和删除语句。可能存在您的代码可能需要验证的情况,我没有提到这些情况,这是因为其他所有情况似乎都是有序的并且"并发冲突"仍然存在。在花费数小时调试之前,一个好的起点就是解决如何处理更新。
打开数据集设计器 单击表适配器。 在属性中,展开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子句可以使用主键形成。
在我的情况下,更新是在没有用户参与的情况下完成的,因此使用主键是有意义的。如果您了解行为的原因和原因,则需要根据您的环境进行调整。