DataTable的AcceptChanges()方法和DataRow的RowState屬性


這個屬性是一個只讀屬性的枚舉類型,一共有五個值,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()這個方法后,所有 AddedModified 行都變為 Unchanged, ,和 Deleted 行也被刪除。

AcceptChanges

所以這個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()是對程序的一種優化)

運行之后控制台輸出:

AcceptChanges2

很明顯,調用之前和之后,RowState由Modified變為了Unchanged了,讓我們來看一下數據庫中的張三有沒有變為小紅?

AcceptChange1

      有人會開始罵人了惡魔惡魔,怎么張三還在?我修改了呀,而且我還保存了(也就是調用了AcceptChanges方法),根據控制台的打印輸出,內存里面的數據的確改了,怎么數據庫中沒有改變呢?

      那是因為我上面講的SqlCommandBuilder是根據行的狀態RowState和主鍵來生成sql語句的,但是調用AcceptChanges方法又會改變RowState【所有 AddedModified 行都變為 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]);//這里也是索引器的使用========
          }
            
     }

這下數據中的數據就同步了:

AcceptChanges4

所以AcceptChanges()要在Update()方法之后調用,而且當Update()之后,最好調用下AcceptChanges(),是為了將DataState重置,

以免下次Update()會出現

再加一句,DataView也有相似的屬性。

【點擊此處回到主頁】


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM