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

DataTable的AcceptChanges()方法和DataRow的RowState属性这个属性是一个只读属性的枚举类型,一共有五个值,Detached,Unchanged,Added,Deleteed,Modified,属性名值备注Detached1已创建该行,但是该行不属于该表,要么刚刚创建该行,还未添加到表中,要么这行被调用了Remove()或者RemoveAt()方法Unchanged2自上次调用Acc…

这个属性是一个只读属性的枚举类型,一共有五个值,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也有相似的属性。

【点击此处回到主页】

转载于:https://www.cnblogs.com/daimajun/p/6537958.html

今天的文章DataTable的AcceptChanges()方法和DataRow的RowState属性分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/33735.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注