使用 SqlDataAdapter 配合 SqlTransaction 實現資料集的批次更新與異常回滾,確保資料一致性。本文提供可直接套用的標準模式程式碼。
public void UpdateContactTableByDataSet(DataSet ds, string tableName)
{
using (var conn = new SqlConnection(connectionString))
using (var adapter = new SqlDataAdapter($"SELECT * FROM {tableName}", conn))
using (var cmdBuilder = new SqlCommandBuilder(adapter))
{
conn.Open();
using (var tran = conn.BeginTransaction())
{
adapter.SelectCommand.Transaction = tran;
adapter.InsertCommand.Transaction = tran;
adapter.UpdateCommand.Transaction = tran;
adapter.DeleteCommand.Transaction = tran;
try
{
adapter.Update(ds, tableName);
tran.Commit();
}
catch (Exception ex)
{
try { tran.Rollback(); }
catch (SqlException rbEx)
{
if (tran.Connection != null)
Log.Error($"回滾失敗: {rbEx}");
}
throw; // 重新拋出原始異常
}
}
}
}
SqlCommandBuilder 根據 SelectCommand 自動產生 Insert/Update/DeleteCommand,需查詢包含主鍵。Command 必須共用同一 SqlTransaction 實例。using 中自動 Dispose/Close。throw;:保留完整堆疊追蹤,勿用 throw ex;。SqlDataAdapter.UpdateBatchSize (預設 1) 可啟用批次提交,減少網路往返:
adapter.UpdateBatchSize = 100; // 每 100 筆打包一次
需 SQL Server 2008+ 且命令為參數化 SQL (CommandBuilder 自動產生即符合)。
現代專案建議使用 EF Core:
using (var ctx = new MyDbContext())
using (var tran = ctx.Database.BeginTransaction())
{
try
{
ctx.BulkUpdate(entities); // 或 ctx.SaveChanges();
tran.Commit();
}
catch { tran.Rollback(); throw; }
}
EF Core 內建變更追蹤、樂觀並行、交易支援,程式碼更簡潔且型別安全。