WinForms操作Access数据库按ID删行重启后数据未生效问题
问题场景
在这段代码中,逻辑为获取选中行ID后执行SQL命令删除对应行:
// Ask for Confirmation DialogResult response = MessageBox.Show("Tem a certeza?", "Apagar?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2); // ID of the row int deleteid = (int)((DataRowView)sfDataGrid1.SelectedItem).Row.ItemArray[0]; // Tabela is the name of the table query = "DELETE FROM " + Tabela + " WHERE ID = " + deleteid; oleDbCommand = new OleDbCommand(query, connection); if (response == DialogResult.Yes) { try { oleDbCommand.ExecuteNonQuery(); // Says that data was deleted MessageBox.Show("Dados apagados com sucesso", "", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { // Show error message MessageBox.Show("Não foi possivel apagar os dados.\n " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } else { // Cancels the Action MessageBox.Show("Cancelado", "", MessageBoxButtons.OK, MessageBoxIcon.Warning); } // Update the DataGridView UpdateTable();
异常现象
- 代码运行无报错,弹出删除成功提示,但重启程序后被删除的数据仍然存在
- 尝试多种SQL写法结果完全一致,执行的命令示例如下:
"DELETE FROM tab_tasks WHERE ID = 2"
- 命令执行无报错,但修改未实际持久化到Access数据库
附UpdateTable()方法实现:
public void UpdateTable() { if (connection.State == ConnectionState.Closed) { try { connection.ConnectionString = Caminho; connection.Open(); } catch (Exception ex) { MessageBox.Show(ex.Message); } } DataSet dset = new DataSet(); if (Tabela == "tab_tasks") { DataSet1TableAdapters.DataTable1TableAdapter dadapter = new DataSet1TableAdapters.DataTable1TableAdapter(); DataSet1.DataTable1DataTable dt = new DataSet1.DataTable1DataTable(); dadapter.Fill(dt); sfDataGrid1.DataSource = null; sfDataGrid1.DataSource = dt; } Modify_Button.Enabled = false; Remove_Button.Enabled = false; sfDataGrid1.Update(); connection.Close(); }
补充说明:代码中添加表名判断是因为数据库包含多张表,DataGrid需要展示不同表的关联列(tab_tasks表的SubTasksId与tab_subtasks表的ID字段值一致)。需要定位问题原因,实现删除更改持久化保存到Access数据库。
问题原因
90%以上的同类Access数据库操作不持久问题,都是项目中数据库文件的复制配置错误导致的:
Visual Studio默认会把项目内引入的Access文件的「复制到输出目录」属性设为「始终复制」,每次启动调试程序时,都会把项目根目录下的原始数据库文件,完整覆盖到程序运行的输出目录(bin/Debug或bin/Release文件夹)。执行删除操作修改的是输出目录里的数据库副本,下次启动程序时原始未修改的库文件又会覆盖这个副本,看起来就像删除操作从来没生效过。
剩余少部分情况由以下原因导致:
- 删除操作实际未匹配到任何行,代码没有校验
ExecuteNonQuery()的返回受影响行数,误判为执行成功 - 数据库文件存放在Program Files等系统受保护目录,Windows UAC虚拟化将写入操作重定向到了虚拟存储路径,程序实际没有修改原数据库文件
- 数据库操作使用的连接字符串指向的数据库文件路径,和重启后查看的数据库文件不是同一个
修复方案
按照优先级依次操作即可:
- 修改数据库文件复制配置
- 在解决方案资源管理器中找到项目内的Access数据库文件(.mdb/.accdb后缀),右键选择「属性」
- 找到「复制到输出目录」配置项,将默认的「始终复制」修改为*「如果较新则复制」*
- 修改后只有手动更新项目根目录下的原始数据库文件时,才会覆盖输出目录的运行库,程序运行时对数据库的修改会被保留。
- 增加删除操作结果校验
- 替换原有无返回值的执行逻辑,判断实际受影响的行数,避免假成功:
// 替换原来的 oleDbCommand.ExecuteNonQuery(); int affected = oleDbCommand.ExecuteNonQuery(); if (affected == 0) { MessageBox.Show("未找到对应ID的数据,删除未生效"); return; } - 排查路径和权限问题
- 不要把数据库文件放在Program Files、系统盘根目录等需要管理员权限才能写入的路径,避免UAC重定向
- 调试时可以在代码中打印
connection.DataSource的值,确认程序运行时连接的确实是预期路径下的数据库文件,避免连错文件。
- 可选优化
- 用
using块包裹OleDbConnection、OleDbCommand等非托管资源对象,避免连接泄漏 - 改用参数化查询拼接SQL,避免字符串拼接带来的SQL注入、特殊字符语法错误问题。
- 用
内容的提问来源于stack exchange,提问作者AcisSys
相关产品推荐
相关产品推荐

