基于DataSet多表更新数据库的实现咨询
基于DataSet多表更新数据库的实现咨询
嘿,我来帮你梳理解决这个多表更新的问题!先看看你的场景和疑问:
我有一个应用,里面包含多个DataTables的编辑器,这些表都存储在一个DataSet中,我通过DataAdapter加载数据。我的目标是把所有表中的变更都更新到数据库里。我原本想复用加载数据时用的同一个DataAdapter,搭配CommandBuilder来实现,就像处理单个DataTable那样。
这是我加载DataSet的代码:
using (SqlConnection con = new SqlConnection(ConnectionString)) { con.Open(); var query = "SELECT * FROM Parameters; SELECT * FROM Status; SELECT * FROM Commands;"; var selectCommand = new SqlCommand(query, con); DataAdapter = new SqlDataAdapter(selectCommand); DataAdapter.AcceptChangesDuringFill = DataAdapter.AcceptChangesDuringUpdate = true; DataAdapter.TableMappings.Add("Table", "Parameters"); DataAdapter.TableMappings.Add("Table1", "Status"); DataAdapter.TableMappings.Add("Table2", "Commands"); // 代码未完成部分省略 }
首先得给你提个醒:单个CommandBuilder没法处理多表的更新逻辑。因为CommandBuilder是基于单个SelectCommand生成对应增删改命令的,而你的DataAdapter里的SelectCommand是多表查询语句,它没办法自动识别每个表的结构,也就没法为每个表生成正确的更新命令。
不过别担心,有两种靠谱的方案可以实现你的需求:
方案一:为每个DataTable单独创建DataAdapter和CommandBuilder
这是最直观也最不容易出错的方式,给每个表配专属的DataAdapter和CommandBuilder,分别处理更新:
using (SqlConnection con = new SqlConnection(ConnectionString)) { con.Open(); // 处理Parameters表的更新 var paraAdapter = new SqlDataAdapter("SELECT * FROM Parameters", con); var paraCmdBuilder = new SqlCommandBuilder(paraAdapter); paraAdapter.Update(dataSet.Tables["Parameters"]); // 处理Status表的更新 var statusAdapter = new SqlDataAdapter("SELECT * FROM Status", con); var statusCmdBuilder = new SqlCommandBuilder(statusAdapter); statusAdapter.Update(dataSet.Tables["Status"]); // 处理Commands表的更新 var cmdAdapter = new SqlDataAdapter("SELECT * FROM Commands", con); var cmdCmdBuilder = new SqlCommandBuilder(cmdAdapter); cmdAdapter.Update(dataSet.Tables["Commands"]); }
方案二:手动为原DataAdapter配置每个表的更新命令
如果你一定要复用同一个DataAdapter,那得手动为每个表编写对应的Insert、Update、Delete命令,不过这种方式比较繁琐,容易出错,示例大概是这样:
using (SqlConnection con = new SqlConnection(ConnectionString)) { con.Open(); var dataAdapter = new SqlDataAdapter(); // 先设置Parameters表的增删改命令 dataAdapter.SelectCommand = new SqlCommand("SELECT * FROM Parameters", con); dataAdapter.InsertCommand = new SqlCommand("INSERT INTO Parameters (...) VALUES (...)", con); // 绑定InsertCommand的参数,此处省略具体参数绑定逻辑 dataAdapter.UpdateCommand = new SqlCommand("UPDATE Parameters SET ... WHERE ...", con); // 绑定UpdateCommand的参数 dataAdapter.DeleteCommand = new SqlCommand("DELETE FROM Parameters WHERE ...", con); // 绑定DeleteCommand的参数 // 更新Parameters表 dataAdapter.Update(dataSet.Tables["Parameters"]); // 重复上述步骤,为Status表和Commands表重新配置dataAdapter的增删改命令,再分别更新 }
最后给你几个重要的注意点:
- 确保每个DataTable都设置了主键,CommandBuilder必须依赖主键才能生成正确的更新命令,否则可能会批量更新错误的行,甚至直接报错。
- 建议把所有更新操作放在同一个事务里,这样如果某一步更新失败,所有变更都能回滚,保证数据一致性(代码示例如下):
using (SqlConnection con = new SqlConnection(ConnectionString)) { con.Open(); using (SqlTransaction tran = con.BeginTransaction()) { try { var paraAdapter = new SqlDataAdapter("SELECT * FROM Parameters", con); paraAdapter.SelectCommand.Transaction = tran; var paraCmdBuilder = new SqlCommandBuilder(paraAdapter); paraAdapter.Update(dataSet.Tables["Parameters"]); // 其他表的更新同理,都绑定同一个事务 tran.Commit(); } catch (Exception ex) { tran.Rollback(); // 这里处理异常,比如记录日志、提示用户等 } } } - 你代码里设置的
AcceptChangesDuringFill和AcceptChangesDuringUpdate为true是没问题的,但要注意AcceptChangesDuringUpdate设为true后,更新完成的DataRow状态会变成Unchanged,如果后续还有其他操作,要确认这符合你的业务需求。
备注:内容来源于stack exchange,提问作者Sambu
相关产品推荐
相关产品推荐

