因为WPF项目需要,经常要对DataTable 的操作及回滚,因操作存在于多个窗口及方法间,不适用TransactionScope。
于是想到DataTable的Merge操作。
1):首先创建一个DataTable以便测试
因为要回滚,不太适合在原来的DataTable上操作,因此决定创建DataTable的深拷贝。
2):创建DataTable的深拷贝
所有的操作都作用在新产生的DataTable上,
现在不用考虑回滚的问题了,因为新表与旧表没有任何关系了。
当我们要保存操作时,这时候可以用到Merge了,(如果表没有主键,此方法行不通)
让我们看一下行合并时RowState的变化(经自己测试)
现在的问题是当我们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的变化。
于是想到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 为 Added2 {
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 }
因为要回滚,不太适合在原来的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 }
我们创建一份原有数据的Copy2 {
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 }
所有的操作都作用在新产生的DataTable上,
现在不用考虑回滚的问题了,因为新表与旧表没有任何关系了。
当我们要保存操作时,这时候可以用到Merge了,(如果表没有主键,此方法行不通)
让我们看一下行合并时RowState的变化(经自己测试)
原表RowState |
拷贝RowState |
合并后的oldTable |
Added |
Added,Modified,UnChanged |
Added |
Added |
Deleted |
Deleted |
Modified |
Added,Modified,UnChanged |
Modified |
Modified |
Deleted | Deleted |
UnChanged |
Added,Modified,UnChanged |
Modified |
UnChanged |
Deleted |
Deleted |
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的变化。