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

所以这个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【所有 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[]["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属性的更多相关文章

  1. DataRow的RowState属性变化

    DataRow的RowState属性(状态)取值有5种:Detached, Unchanged, Added, Deleted, Modified. 当我们用DataRow newRow = Data ...

  2. 关于Java中的构造方法和set方法()给属性赋值

    对于一个类中的成员变量(属性),属性如果都设置成了private类型,那么对外给属性设置了get和set方法 , 那么外部程序中给这些属性设置值,有两种方式. 第一种就是通过set()方法. 第二种就 ...

  3. javascript 之Function对象的apply(),call(),bind(),方法和arguments,caller,length属性

    注:这篇文章原文:http://www.jb51.net/article/30883.htm 自己作为学习,重新写写. 一.写在前面的话 前端javascript编程还只是略懂皮毛,DOM知道一点,j ...

  4. DataTable的AcceptChanges()和RejectChanges()方法

    一.DataTable.AcceptChanges()方法 提交自上次调用AcceptChanges()方法以来对该表进行的所有更改.调用AcceptChanges()时,任何扔处于编辑模式的Data ...

  5. ASP.NET Core 中文文档 第二章 指南(4.10)检查自动生成的Detail方法和Delete方法

    原文 Examining the Details and Delete methods 作者 Rick Anderson 翻译 谢炀(Kiler) 校对 许登洋(Seay).姚阿勇(Mr.Yao) 打 ...

  6. Spark Rdd coalesce()方法和repartition()方法

    在Spark的Rdd中,Rdd是分区的. 有时候需要重新设置Rdd的分区数量,比如Rdd的分区中,Rdd分区比较多,但是每个Rdd的数据量比较小,需要设置一个比较合理的分区.或者需要把Rdd的分区数量 ...

  7. ThinkPHP的D方法和M方法的区别

    M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...

  8. 精益化设计:把敏捷方法和Lean UX相结合

    敏捷方法已经成为了主流.同时,Kindle和iPhone等设备取得的巨大成功也推动了体验设计的飞速发展.不过,如何把敏捷方法和UX设计结合起来,一直以来都是一个难题.文章将探讨如何把UX融入到最流行的 ...

  9. Hibernate中evict方法和clear方法说明

    Hibernate中evict方法和clear方法说明 先创建一个对象,然后调用session.save方法,然后调用evict方法把该对象清除出缓存,最后提交事务.结果报错: Exception i ...

随机推荐

  1. Windows 10 IoT Serials 5 - 如何为树莓派应用程序添加语音识别与交互功能

    都说语音是人机交互的重要手段,虽然个人觉得在大庭广众之下,对着手机发号施令会显得有些尴尬.但是在资源受限的物联网应用场景下(无法外接鼠标键盘显示器),如果能够通过语音来控制设备,与设备进行交互,那还是 ...

  2. MongoDB基础之十 shared分片

    水平分片实例分布图: mongodb sharding 服务器架构   1. 添加mongdb两个shared实例 # mkdir -p /home/m17 //home/m18 /home/m20 ...

  3. vue2重写饿了么

    构建 vue有自己的脚手架构建工具vue-cli,使用起来非常方便,使用webpack来集成各种开发便捷工具,比如: 代码热更新,修改代码之后网页无刷新改变,对前端开发来说非常的方便 PostCss, ...

  4. C语言 extern3 全局变量的使用

    和函数的全局使用极其类似: 第一种方法,也是最简单的: 在 first.h 中定义, ; 在对应的first.c中使用: #include "first.h" #include & ...

  5. AspNet Identity 和 Owin 谁是谁

    英文原文:http://tech.trailmax.info/2014/08/aspnet-identity-and-owin-who-is-who/ 最近我发现Stackoverflow上有一个非常 ...

  6. js字符串转日期,js字符串解析成日期,js日期解析, Date.parse小时是8点,Date.parse时间多了8小时

    js字符串转日期,js字符串解析成日期,js日期解析, Date.parse小时是8点,Date.parse时间多了8小时 >>>>>>>>>&g ...

  7. MASM32快速起步

    MASM32是一个免费的软件程序,让您编辑Microsoft宏汇编程序(MASM)代码从一个基本的文本界面.它强调MASM代码各部分以不同的颜色,使其更容易扫描和检测错误.它提供了一个简单的布局程序员 ...

  8. JAVA集合一之集合简介(Collection,List,Set)

    在编写JAVA程序中,我们经常会遇到需要保存一组数据对象,此时,我们可以采用对象数组来进行多个对象的保存,但对象数组存在一个最大的问题即在于长度上的限制,如果说我们现在要保存一组对象,但是我们并知道数 ...

  9. 读书笔记 effective c++ Item 19 像设计类型(type)一样设计

    1. 你需要重视类的设计 c++同其他面向对象编程语言一样,定义了一个新的类就相当于定义了一个新的类型(type),因此作为一个c++开发人员,大量时间会被花费在扩张你的类型系统上面.这意味着你不仅仅 ...

  10. 【转】Java中关于异常处理的十个最佳实践

    原文地址:http://www.searchsoa.com.cn/showcontent_71960.htm 导读:异常处理是书写强健Java应用的一个重要部分,Java许你创建新的异常,并通过使用 ...