一、先说一下Datarow的结构(如图所示):
图1
二、DataRow.rowstate属性的改变(判断rowstate的依据是datarow中original,current和proposed的指向是否为NULL以及他们所指向的对象是否相同)
1、创建一个新的datarow
datarow row=tb.newrow();//tb包含两列:ID(自增,int类型);Name(string类型)
row["Name"]="xiao";
此时产生的新行还没有进入tb的行集合中,row.rowstate的值为:Detached(表示该行不是datatable的一个成员)
图2
2、tb.rows.add(row);
把row加入到tb的行集合中,此时proposed不再指向row对象而有current指向row对象,rowstate的值为Added。如图所示:
图3
3、如果向数据添加成功(即完成commit),为了与后台数据保持一致,故应该执行acceptchanges()方法,使original和current都指向row对象,同时rowstate的值为unchanged。如图所示:
图4
如果向数据添加失败而造成回滚(rollback),此时应该执行rejectchanges()方法,将会从datarow的行集合中移除datarow,并将row的rowstate设置为Detached。
4、修改现有行
方法一:
row["Name"]="da";
方法二:
row.BeginEdit();
row["Name"]="da";
row.EndEdit();
这两种方法的区别:第一、使用BeginEdit和EndEit可以缓冲对数据行的更改。例如:采用第一种方法,修改将对current所指向的对象中Name进行修改,此时rowstate的值为modified;采用第二种方法,将形成一个新对象(Name为da),proposed指向该对象,故rowstate的值仍旧为unchanged。当调用EndEdit的时候才对行的更改进行保存(即current指向形成的新对象,此时rowstate的值为modified)。如果确定不希望保存这些更改,可以调用CancelEdit来撤销这些更改,该行将返回调用BeginEdit的状态。第二、datatable中拥有RowChanging,RowChanged,ColumnChanging和ColumnChanged等事件,可用于查看对一行或一列的更改。在第一种方法中,每次修改行中的一列或多列,datatable类的事件都会激发。使用BeginEdit将中断事件的激发,直到调用EndEdit为止(如果调用CancelEdit而不是EndEdit,所缓存的更改将被丢失,因为该行未被更新,所以这些事件不会激发)。
下图所展示的是第二种方法修改的说明图:
图6:当调用rejectChanges方法时
图5:当调用acceptchanges方法时,proposed会拷贝current内荣
当后台数据库修改成功(执行了commit命令)话,前台执行acceptchanges()方法,此时把current的内容拷贝给original。如果后台数据库修改失败(执行了rollback命令)话,前台执行rejectchanges()方法,此时把original的内容拷贝给current。此时,rowstate值为unchanged。
4、删除DataRow
row.delete();
删除数据行并没有将其从DataTable中移除,而是由ADO.NET将该行标记为挂起删除。此时rowstate的属性值:deleted。如下图所示:
图7
如果在后台数据库中删除操作执行成功(即使用了commit命令),前台调用acceptchanges()方法将会从DataTable的行集合中移除datarow,并将datarow的rowstate值改为Detached。如果在后台数据库中删除操作执行失败(即使用了rollback命令),前台调用rejectchanges()方法会把original的内容拷贝给current中去,此时rowstate值恢复到unchanged。5、
5、移除DataRow
row.remove或者row.removeAt(),这两个方法作用是:从DataTable中移除一个数据行,而不是将其标记为挂起删除。该方法相当于:先调用delete(),然后再调用acceptchanges()方法。
6、datarow的这三行可以解决乐观并发模式中丢失修改问题。例如可以写如下的sql语句:
update tb set Name=‘hd’ where Id=1 and Name=originalvalue;