因为WPF项目需要,经常要对DataTable 的操作及回滚,因操作存在于多个窗口及方法间,不适用TransactionScope。 于是想到DataTable的Merge操作。 1):首先创建一个DataTable以便测试
现在的问题是当我们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的变化。
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 的RowStateoldTable.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 |