因为WPF项目需要,经常要对DataTable 的操作及回滚,因操作存在于多个窗口及方法间,不适用TransactionScope。
于是想到DataTable的Merge操作。

1):首先创建一个DataTable以便测试

 1         static DataTable CreateTestTable()
 2         {
 3             var dt = new DataTable();
 4             var dc = new DataColumn("ID"typeof(int));
 5             dt.Columns.Add(dc);
 6             dt.PrimaryKey = new DataColumn[] { dc };
 7             for (var i = 0; i < 10; i++)
 8             {
 9                 var dr = dt.NewRow();
10                 dr[dc] = i;
                    dt.Rows.Add(dr);
11             }
12             return dt;
13         }
很显然,所有的DataRow插入时,RowState 为 Added
因为要回滚,不太适合在原来的DataTable上操作,因此决定创建DataTable的深拷贝。
2):创建DataTable的深拷贝

 1   static DataTable CreateDeepCopyOfDataTable(DataTable oldTable)
 2         {
 3             var ms = new MemoryStream();
 4             BinaryFormatter bf = new BinaryFormatter();
 5             bf.Serialize(ms, oldTable);
 6             ms.Seek(0, SeekOrigin.Begin);
 7             var newTable = bf.Deserialize(ms) as DataTable;
 8             ms.Close();
 9             return newTable;
10         }
我们创建一份原有数据的Copy
所有的操作都作用在新产生的DataTable上,
现在不用考虑回滚的问题了,因为新表与旧表没有任何关系了。
当我们要保存操作时,这时候可以用到Merge了,(如果表没有主键,此方法行不通)
让我们看一下行合并时RowState的变化(经自己测试)

原表RowState
oldTable

拷贝RowState
newTable

合并后的oldTable
RowState
oldTable.Merge(newTable);

Added

Added,Modified,UnChanged

Added

Added

Deleted

Deleted

Modified

 Added,Modified,UnChanged

 Modified

Modified

Deleted Deleted

UnChanged

Added,Modified,UnChanged

Modified

UnChanged

Deleted

Deleted

现在的问题是当我们Delete(Row.Delete();)掉DataTable中的一行时,如果这一行原先的状态为
Added时,他的状态会变成Detached,表示这一行已经从DataTable.Rows中删掉了,相当于
DataTable.Rows.Remove(row);
而DataRow.Delete() 只是改变DataRow 的RowState.
并没有将DataRow 从DataTable的Rows集合中去除。
这个时候,假如原表中有一行为Added.而拷贝的表中这一行执行了Delete之后,这一行的RowState
会变成Detached,当合并时,原表里的这一行因为找不到任何匹配的主键,
所以不会发行变化,从而导致合并后的数据不正确。
解决方法很简单,在拷贝的表执行Row.Delete的时候,将其RowState设为UnChanged.(调用AcceptChagnes方法)
然后再执行Row.Delete();

本文并非要给出一个好的方法来实现DataTable 的回滚,而是分析对DataRow操作时,
其RowState的变化。