DataTable的AcceptChanges()方法和DataRow的RowS…
2018-06-17 19:10:36来源:未知 阅读 ()
这个属性是一个只读属性的枚举类型,一共有五个值,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也有相似的属性。
【点击此处回到主页】
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- Delphi 调用C# 编写的DLL方法 2019-10-28
- PHP保留两位小数的几种方法 2019-08-16
- 委托学习笔记后续:泛型委托及委托中所涉及到匿名方法、Lamb 2018-06-21
- MVC学习一:EF 2018-06-21
- extern外部方法使用C#简单例子 2018-06-21
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash