今天我遇到一個題目,是關於AcceptChanges()和RejectChanges()方法的,考慮到可能很多人不清楚這些概念。
所以拿出來講講。由這個問題我們也深入了解一下這兩個方法。
為了不在顯示略文時顯示出代碼來,我就在剛開始多打一點字了。呵。。。
題目的代碼如下:
protected void Button1_Click(object sender, EventArgs e)
{
DataSet ds= new DataSet();
DataTable tb = ds.Tables.Add("Items");
DataColumn pk = tb.Columns.Add("ID", typeof(Int32));
tb.Columns.Add("Items", typeof(string));
tb.PrimaryKey = new DataColumn[] {pk};
for(int i=0;i<6;i++)
{
DataRow dr = tb.NewRow();
dr[0] = i.ToString();
dr[1] = "Itme "+i;
tb.Rows.Add(dr);
}
tb.Rows[0].Delete();
tb.Rows.RemoveAt(1);
tb.Rows.RemoveAt(2);
tb.RejectChanges();
GridView1.DataSource = tb;
GridView1.DataBind();
}
我們看到在第3-16行,實際上我們是生成了一個DataTable,這個dt有兩個字段,分別是ID和Items,然后通過添加6條記錄。
如果到此為止,那么這個的內容應該是如下:
| ID | Items |
| 0 | Item 0 |
| 1 | Item 1 |
| 2 | Item 2 |
| 3 | Item 3 |
| 4 | Item 4 |
| 5 | Item 5 |
不過我們在第19,20,21行中分別刪除了第0行,然后是移除第1行,移除第2行。當然如果只是這樣就算不上題目了,我們在18和22行用到了DataTable的AcceptChanges()方法和RejectChanages()方法。
首先大家先想一下答案是什么?隨便我把MSDN上對這兩個方法的解釋粘一下,好讓大家理解。
DataTable.AcceptChanges方法
提交自上次調用 AcceptChanges 以來對該表進行的所有更改。調用 AcceptChanges 時,任何仍處於編輯模式的 DataRow 對象將成功結束其編輯。DataRowState 也會隨之更改:所有狀態為 Added 和 Modified 的行的狀態都變為 Unchanged;狀態為 Deleted 的行則被移除。
在您嘗試使用 DbDataAdapter.Update 方法更新 DataSet 之后,通常會對 DataTable 調用 AcceptChanges 方法。
DataTable.RejectChanges方法
回滾自該表加載以來或上次調用 AcceptChanges 以來對該表進行的所有更改。
調用 RejectChanges 時,任何仍處於編輯模式的 DataRow 對象將取消其編輯。新行被移除。DataRowState 設置為 Modified 或 Deleted 的行返回到其初始狀態。
一個意思表示立即更新,一個表示在接受上次調用AcceptChanges后進行回滾。
好的,那么是不是說,我們這兒的3條記錄都能夠回滾回來呢?
我們先公布一下答案吧,看看和大家想的是不是一樣的。
| ID | Items |
| 0 | Item 0 |
| 2 | Item 2 |
| 4 | Item 4 |
| 5 | Item 5 |
OK,答案表明並不是所有的記錄都被回滾回來了,似乎只有0被回滾了。這並不是奇怪,那是因為我們使用刪除行的方法不一樣,一個是Delete(),一個是RemoveAt(int)。
我們通過在MSDN中的查詢了解到在使用 Delete 方法后,RowState 變成“已刪除”。在您調用 AcceptChanges 之前,它一直保持“已刪除”。可通過調用 RejectChanges 取消刪除行。
而RemoveAt表示當移除行時,該行中的所有數據都將丟失。您還可以調用 DataRow 類的 Delete 方法來標記某行以供移除。調用 RemoveAt 等同於先調用 Delete 再調用 AcceptChanges。
那就是說,我們使用Delete()方法刪除行后是可以回滾的,而使用RemoveAt(int)方法是不能回滾的。
所以剛剛前面我們刪除的三行,只回滾了0的那行是完成正確的。我想大家對答案應該沒有疑問了。
從這個題目中,我引申出幾個題目來,看看大家會不會做哦?
下面接着,我們再來修改一下代碼看看。
tb.Rows[
0
].Delete();
tb.AcceptChanges();
tb.Rows.RemoveAt(
1
);
tb.Rows.RemoveAt(
2
);
tb.RejectChanges();
我們把AcceptChanges()方法放到后Delete()后面,很明顯這樣做,會讓ID為0的數據也無法回滾。為什么大家看我上面粘的MSDN解釋就知道了。
那么就這的話,答案會是什么呢,會不會有人想到是2,4,5呢。
想到2,4,5的人就錯了哦。因為當接受AcceptChanges()方法后,前面的0行就徹底刪除了,這時數據應該是1,2,3,4,5,然后RemoveAt(1)表示刪除第2行,刪除后也是立刻刪除的,無法回滾,所以這時數據應該是1,3,4,5,接着RemoveAt(2)刪除第3行,所以答案應該是1,3,5。
而原來把AcceptChanage()方法放在Delete()前面時,當調用tb.Rows[0].Delete()時,只是標記狀態為刪除,並沒有直接移除第0行,所以那個RemoveAt(1),還是從0,1,2,3,4,5中刪除第2行,所以答案是0,2,4,5。
好,我們再修改一下代碼:
tb.AcceptChanges();
tb.Rows[
0
].Delete();
tb.Rows.RemoveAt(
1
);
tb.AcceptChanges();
tb.Rows.RemoveAt(
2
);
tb.RejectChanges();
大家來猜猜答案是什么呢?
不知道有沒有人想到會是2,4,5,實際上不對。
正確的答案應該是2,3,5。
首先的第一個AcceptChanages表示將無法回滾前面添加數據的操作。接着第二個AcceptChanages表示徹底刪除Delete()所刪除的數據,這個時候數據就只剩下2,3,4,5了,然后再RemoveAt(2)把第三行刪除了,所以就剩下2,3,5了。
好的,我們再把第一個AcceptChanages()方法給刪除了,大家想想答案會是什么呢,代碼如下:
tb.Rows[
0
].Delete();
tb.Rows.RemoveAt(
1
);
tb.AcceptChanges();
tb.Rows.RemoveAt(
2
);
tb.RejectChanges();
可能有人說了,AcceptChanages()方法是對前面的語句生效的,所以你把這個刪除了一點問題也沒有,答案當然還是2,3,5了,其實這種說法是錯誤的。
這段代碼的正確答案是1,3,5。
為什么會是這樣呢,那是因為當Delete()方法在前面沒有接收到AcceptChaages()方法后,會徹底刪除因為沒有必要回滾。所以RemoveAt(1)在執行時,實際上數據是1,2,3,4,5,它刪除第2行,也就是3。
好的,我們再看看下面的這段代碼:
tb.Rows[
0
].Delete();
tb.Rows.RemoveAt(
1
);
tb.Rows.RemoveAt(
2
);
tb.AcceptChanges();
tb.RejectChanges();
不知道有沒有人會笑話我,實際上這段代碼和上面的代碼是一個效果哦。
那么我們再看看這段代碼呢?
tb.Rows[
0
].Delete();
tb.Rows.RemoveAt(
1
);
tb.Rows.RemoveAt(
2
);
tb.RejectChanges();
