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()这个方法后,所有 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[]["sname"] = "小红";//这里是索引器的使用===========================
Console.WriteLine("调用AcceptChanges方法之前第一行的RowState属性 :" + dataTable.Rows[].RowState);//这里是调用AcceptChanges方法之前该行的RowState属性
//注意:我是在Update之前调用的AcceptChanges方法
dataTable.AcceptChanges();
Console.WriteLine("调用AcceptChanges方法之后第一行的RowState属性 :" + dataTable.Rows[].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[] + ", " + row[] + ", " + row[] + ", " + row[]);//索引器的使用======================
}
}
(对于上面代码中的红色字,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[]["sname"] = "小红";//这里是索引器的使用===================
Console.WriteLine("调用AcceptChanges方法之前第一行的RowState属性 :" + dataTable.Rows[].RowState);//这里是调用AcceptChanges方法之前该行的RowState属性
//注意:我是在Update之前调用的AcceptChanges方法
//dataTable.AcceptChanges();
SqlCommandBuilder scb = new SqlCommandBuilder(adapter);
adapter.Update(dataTable);
//注意:我是在Update之后调用的
dataTable.AcceptChanges();
Console.WriteLine("调用AcceptChanges方法之后第一行的RowState属性 :" + dataTable.Rows[].RowState);//这里是调用AcceptChanges方法之后该行的RowState属性
//下面是一个遍历输出datatable中的数据
foreach(DataRow row in table.Rows)
{
Console.WriteLine(row[] + ", " + row[] + ", " + row[] + ", " + row[]);//这里也是索引器的使用========
} }
这下数据中的数据就同步了:

所以AcceptChanges()要在Update()方法之后调用,而且当Update()之后,最好调用下AcceptChanges(),是为了将DataState重置,
以免下次Update()会出现
再加一句,DataView也有相似的属性。
DataTable的AcceptChanges()方法和DataRow的RowState属性的更多相关文章
- DataRow的RowState属性变化
DataRow的RowState属性(状态)取值有5种:Detached, Unchanged, Added, Deleted, Modified. 当我们用DataRow newRow = Data ...
- 关于Java中的构造方法和set方法()给属性赋值
对于一个类中的成员变量(属性),属性如果都设置成了private类型,那么对外给属性设置了get和set方法 , 那么外部程序中给这些属性设置值,有两种方式. 第一种就是通过set()方法. 第二种就 ...
- javascript 之Function对象的apply(),call(),bind(),方法和arguments,caller,length属性
注:这篇文章原文:http://www.jb51.net/article/30883.htm 自己作为学习,重新写写. 一.写在前面的话 前端javascript编程还只是略懂皮毛,DOM知道一点,j ...
- DataTable的AcceptChanges()和RejectChanges()方法
一.DataTable.AcceptChanges()方法 提交自上次调用AcceptChanges()方法以来对该表进行的所有更改.调用AcceptChanges()时,任何扔处于编辑模式的Data ...
- ASP.NET Core 中文文档 第二章 指南(4.10)检查自动生成的Detail方法和Delete方法
原文 Examining the Details and Delete methods 作者 Rick Anderson 翻译 谢炀(Kiler) 校对 许登洋(Seay).姚阿勇(Mr.Yao) 打 ...
- Spark Rdd coalesce()方法和repartition()方法
在Spark的Rdd中,Rdd是分区的. 有时候需要重新设置Rdd的分区数量,比如Rdd的分区中,Rdd分区比较多,但是每个Rdd的数据量比较小,需要设置一个比较合理的分区.或者需要把Rdd的分区数量 ...
- ThinkPHP的D方法和M方法的区别
M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...
- 精益化设计:把敏捷方法和Lean UX相结合
敏捷方法已经成为了主流.同时,Kindle和iPhone等设备取得的巨大成功也推动了体验设计的飞速发展.不过,如何把敏捷方法和UX设计结合起来,一直以来都是一个难题.文章将探讨如何把UX融入到最流行的 ...
- Hibernate中evict方法和clear方法说明
Hibernate中evict方法和clear方法说明 先创建一个对象,然后调用session.save方法,然后调用evict方法把该对象清除出缓存,最后提交事务.结果报错: Exception i ...
随机推荐
- [html5] 学习笔记- html拖放
拖放是一种常见的特性,即抓取对象以后拖到另一个位置,在HTML5中,拖放是标准的一部分,任何元素都能够拖放. 1.html5拖放:(drag和drop)是HTML5标准的组成部分 拖动开始:ondra ...
- jq实战-表单验证
作为学习的记录,方便大家查看,废话不多说,直接上代码 html 结构: <form action="a.php" method="" class=&quo ...
- .net 网站应对压力的一些方案总结
开年比较空,抽时间写个博文,总结下自己工作里的一些应对网站访问压力的技术方案. 自己项目现在大概一天50W的pv.已从前端到后端的顺序总结下自己用的一些方案. 一. 前端页面: 1.首先减少资源的大小 ...
- react native 添加第三方插件react-native-orientation(横竖屏设置功能 android)
Installation 1.install rnpm Run npm install -g rnpm 2.via rnpm Run rnpm install react-native-orien ...
- java二维数组学习(转)
转自:http://blog.csdn.net/java1992/article/details/5808709,在这里谢过了 /* * java学习: * 二维数组的使用: */public cla ...
- 重新认识一个强大的 Gson
从一个 Bug 说起 不知道你们发现没有,你写完的程序无论当时怎么测试,过一段时间总会出 Bug .再说一个每天都在发生的例子:在你写完一篇博客后,立即检查的话,总是查不出自己写的错别字. 据说这些都 ...
- 【UWP】拖拽列表项的排序功能实现
在一些允许用户自定义栏目顺序的app(如:凤凰新闻.网易云音乐等),我们可以方便地拖拽列表项来完成列表的重新排序,进而完成对栏目顺序的重排.这个功能很人性化,而实现起来其实很简单(甚至都不用写什么后台 ...
- 核心动画(UIView封装动画)
一.UIView动画(首尾) 1.简单说明 UIKit直接将动画集成到UIView类中,当内部的一些属性发生改变时,UIView将为这些改变提供动画支持 执行动画所需要的工作由UIView类自动完成, ...
- 如何在shell脚本中导出数组供子进程使用
功能说明:设置或显示环境变量. 语 法:export [-fnp][变量名称]=[变量设置值] 补充说明:在shell中执行程序时,shell会提供一组环境变量.export可新增,修改或删除环境变量 ...
- iOS仿微博客户端一条微博的布局
前言 做一个微博客户端的第三方是自学的第一个实践的项目,自从从事iOS工作之后,就把这个项目给搁置了.趁现在过年回来有些空闲时间,再次修改(总觉得项目就是不停地修改).并且记录一点东西,以后可再回头看 ...