這個屬性是一個只讀屬性的枚舉類型,一共有五個值,Detached,Unchanged,Added,Deleteed,Modified,
屬性名 | 值 | 備注 |
Detached | 1 | 已創建該行,但是該行不屬於該表,要么剛剛創建該行,還未添加到表中, 要么這行被調用了Remove()或者RemoveAt()方法 |
Unchanged | 2 | 自上次調用AcceptChanges()方法后,該行未改變 |
Added | 4 | 已經添加到表中,但是AcceptChanges()方法還未調用 |
Deleted | 8 | 該行已通過Delete()被刪除,但是AcceptChanges()方法還未調用 |
Modified | 16 | 該行已被修改,但AcceptChanges 尚未調用 |
這個狀態標志位有很大的作用,它用於被SqlCommandBuilder翻譯T-Sql語句(但僅僅是單表而已),當然還要有主鍵,如果數據表中沒有主鍵,將會報錯“對於不返回任何鍵列信息的 SelectCommand,不支持 UpdateCommand 的動態 SQL 生成。”
當DataTable調用AcceptChange()這個方法后,所有 Added 和 Modified 行都變為 Unchanged, ,和 Deleted 行也被刪除。
所以這個AcceptChange()一定要在DataAdapter調用Update()方法后才調用,不然SqlCommandBuilder就會找不到被修改的行,這樣一來,DataSet中的表被修改了,但是Update到數據庫時,卻不能同步修改。
舉個例子來說明問題:
--建庫建表語句 create database student; use student; create table student( sname varchar(10) not null, sno int not null, sage int not null, ssex varchar(2) not null ); alter table student add constraint PK_sno primary key (sno), constraint CK_ssex check(ssex = '男' or ssex = '女'), constraint CK_sage check(sage > 8 and sage < 40) insert into student values('張三', 103, 23, '男'); insert into student values('李四', 104, 24, '男'); insert into student values('王五', 105, 25, '男'); insert into student values('趙六', 106, 26, '男'); insert into student values('朱七', 107, 27, '男'); select * from student;
C#中的代碼:
public static void AdapterAndSqlCommand() { //第一步:獲取數據庫配置信息 String connStr = ConfigurationManager.ConnectionStrings["connStr"].ToString();//這里是索引器的使用======== //第二步:構建SqlCommand查詢語句 SqlCommand command = new SqlCommand("select * from student;"); command.Connection = new SqlConnection(connStr); //第三步:創建SqlDataAdapter SqlDataAdapter adapter = new SqlDataAdapter(command); //第四步:創建DataTable DataTable dataTable = new DataTable(); //第五步:填充數據 adapter.Fill(dataTable); //修改第一行數據中的姓名 dataTable.Rows[0]["sname"] = "小紅";//這里是索引器的使用=========================== Console.WriteLine("調用AcceptChanges方法之前第一行的RowState屬性 :" + dataTable.Rows[0].RowState);//這里是調用AcceptChanges方法之前該行的RowState屬性 //注意:我是在Update之前調用的AcceptChanges方法 dataTable.AcceptChanges(); Console.WriteLine("調用AcceptChanges方法之后第一行的RowState屬性 :" + dataTable.Rows[0].RowState);//這里是調用AcceptChanges方法之后該行的RowState屬性 SqlCommandBuilder scb = new SqlCommandBuilder(adapter); adapter.Update(dataTable);//這個地方我特意沒有寫dataTable.GetChanges(),因為寫了的話就不能展現這個錯誤了,會在該行報出空參數異常,如果不知道不能提前調用AcceptChanges方法的話,很難發現是AcceptChanges的錯誤,因為報的錯誤不是AcceptChanges那行,而是Update這行。 //注意:我是在Update之后調用的 //dataTable.AcceptChanges(); //下面是一個遍歷輸出datatable中的數據 foreach(DataRow row in table.Rows) {//這里在遍歷的時候也會判斷一下RowState行標志位,已經調用了Delete()方法的行,不會被打印 Console.WriteLine(row[0] + ", " + row[1] + ", " + row[2] + ", " + row[3]);//索引器的使用====================== } }
(對於上面代碼中的紅色字,dataTable.GetChanges()是對程序的一種優化)
運行之后控制台輸出:
很明顯,調用之前和之后,RowState由Modified變為了Unchanged了,讓我們來看一下數據庫中的張三有沒有變為小紅?
有人會開始罵人了,怎么張三還在?我修改了呀,而且我還保存了(也就是調用了AcceptChanges方法),根據控制台的打印輸出,內存里面的數據的確改了,怎么數據庫中沒有改變呢?
那是因為我上面講的SqlCommandBuilder是根據行的狀態RowState和主鍵來生成sql語句的,但是調用AcceptChanges方法又會改變RowState【所有 Added 和 Modified 行都變為 Unchanged, ,和 Deleted 行也被刪除。】,那SqlCommandBuilder就無法對該行生成sql語句了,數據庫當然不會修改數據諾。
正確的做法是在DataAdapter的Update方法調用之后再調用DataTable的AcceptChanges方法,這樣才能保證內存中的數據和數據庫的數據一致。
我們把第一個dataTable.AcceptChanges(); 給注釋掉,打開第二個。
public static void AdapterAndSqlCommand() { //第一步:獲取數據庫配置信息 String connStr = ConfigurationManager.ConnectionStrings["connStr"].ToString();//這里是索引器的使用============== //第二步:構建SqlCommand查詢語句 SqlCommand command = new SqlCommand("select * from student;"); command.Connection = new SqlConnection(connStr); //第三步:創建SqlDataAdapter SqlDataAdapter adapter = new SqlDataAdapter(command); //第四步:創建DataSet和DataTable DataSet dataSet = new DataSet(); DataTable dataTable = new DataTable(); //第五步:填充數據 adapter.Fill(dataTable); //修改第一行數據中的姓名 dataTable.Rows[0]["sname"] = "小紅";//這里是索引器的使用=================== Console.WriteLine("調用AcceptChanges方法之前第一行的RowState屬性 :" + dataTable.Rows[0].RowState);//這里是調用AcceptChanges方法之前該行的RowState屬性 //注意:我是在Update之前調用的AcceptChanges方法 //dataTable.AcceptChanges(); SqlCommandBuilder scb = new SqlCommandBuilder(adapter); adapter.Update(dataTable); //注意:我是在Update之后調用的 dataTable.AcceptChanges(); Console.WriteLine("調用AcceptChanges方法之后第一行的RowState屬性 :" + dataTable.Rows[0].RowState);//這里是調用AcceptChanges方法之后該行的RowState屬性 //下面是一個遍歷輸出datatable中的數據 foreach(DataRow row in table.Rows) { Console.WriteLine(row[0] + ", " + row[1] + ", " + row[2] + ", " + row[3]);//這里也是索引器的使用======== } }
這下數據中的數據就同步了:
所以AcceptChanges()要在Update()方法之后調用,而且當Update()之后,最好調用下AcceptChanges(),是為了將DataState重置,
以免下次Update()會出現
再加一句,DataView也有相似的屬性。