DataAdapter_RowUpdated事件中自增ID未同步至DataSet与DataTable
问题分析与解决方法
问题根源
你通过dataset.Tables[table].GetChanges()生成了独立的changes临时表,后续调用adapter.Update(changes)时,RowUpdated事件中的e.Row指向的是changes表中的行,而非原DataSet里的原始行。直接给e.Row["id"]赋值只会修改临时的changes表,不会同步到原DataSet的表中;同时若未将changes表的变更合并回原表,原表也无法感知到这些更新。
解决步骤
1. 合并临时表变更回原DataSet
在adapter.Update(changes)执行完成后,用Merge方法将临时表的更新同步到原表:
DataTable changes = dataset.Tables[table].GetChanges(); if (changes == null) return 0; SQLiteCommandBuilder scb = new SQLiteCommandBuilder(adapter); scb.ConflictOption = ConflictOption.CompareRowVersion; int cnt = adapter.Update(changes); // 将临时changes表的变更合并回原DataTable dataset.Tables[table].Merge(changes); // 接受原表变更,清除行的编辑状态 dataset.Tables[table].AcceptChanges(); return cnt;
2. 修正RowUpdated事件的行状态
在RowUpdated事件中赋值ID后,标记该行状态为已确认,确保Merge时能识别到变更:
static void adapter_RowUpdated(object sender, System.Data.Common.RowUpdatedEventArgs e) { if (e.StatementType == StatementType.Insert) { SQLiteCommand cmd = new SQLiteCommand("select last_insert_rowid();", conn); object newId = cmd.ExecuteScalar(); if (newId != null) { e.Row["id"] = newId; // 标记该行状态为已完成变更,确保Merge同步生效 e.Row.AcceptChanges(); } } }
3. 替代方案:直接更新原表(无需GetChanges)
如果不需要单独筛选变更行,可以直接调用adapter.Update更新原表,此时RowUpdated事件中的e.Row就是原表的行,赋值后会直接反映到原DataSet:
SQLiteCommandBuilder scb = new SQLiteCommandBuilder(adapter); scb.ConflictOption = ConflictOption.CompareRowVersion; int cnt = adapter.Update(dataset.Tables[table]); return cnt;
这种方式无需额外的Merge操作,更适合无需单独处理变更集的场景。
关键注意事项
last_insert_rowid()仅返回当前连接最后插入的行ID,批量插入若为单条命令插入多行,该方法只会返回最后一行的ID;只有逐行执行插入时,才会返回对应行的ID。- 确保
RowUpdated事件中使用的SQLite连接conn与DataAdapter的连接一致,否则会获取到错误的ID值。
内容的提问来源于stack exchange,提问作者Prahlad Yeri
相关产品推荐
相关产品推荐

