这个属性是一个只读属性的枚举类型,一共有五个值,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. localStorage , sessionStorage ,cookie 使用介绍

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. ActionMode 就记这么一点,不能更多了

    话说程序猿都是段子手,看到有的程序猿写文章,前面都会先写一个段子,我这么有幽默感的段子手,也决定效仿一下. "段子." 写完段子,下面开始进入正题. 今天要说的 ActionMod ...

  3. Webservice_常用

    官网示例: http://cxf.apache.org/docs/writing-a-service-with-spring.html http://cxf.apache.org/docs/jax-r ...

  4. 对Node.JS的事件轮询(Event Loop)的理解

    title: Node.JS的事件轮询(event loop)的理解 categories: 理解 tags: Node JS 机制 当我们知道I/O操作和创建新线程的开销是巨大的! 网站延迟的开销 ...

  5. java中关于转义字符的一个bug

    在java中,你可以定义 char c = '\u4f60'; char m = '\u0045'; char e = '\u554a'; 这样的字面量,例如: System.out.println( ...

  6. 谈谈JavaScript代码混淆

    概述: 案例:Cesium打包流程,相关技术点和大概流程 原理:代码优化的意义:压缩 优化 混淆 优化:如何完善Cesium打包流程 关键字:Cesium gulp uglifyjs 字数:2330 ...

  7. jQuery UI 实例 - 自动完成(Autocomplete)

    http://www.runoob.com/jqueryui/example-autocomplete.html 自定义数据并显示 您可以使用自定义数据格式,并通过简单地重载默认的聚焦和选择行为来显示 ...

  8. IE中使用ajaxSubmit上传文件弹出下载提示框

    使用jQuery的ajaxSubmit 上传文件时,在IE中会弹出下载提示框: 解决方法:让action返回String类型,而不是ActionView,

  9. ReactJS的开发日常

    在用React框架开发的日子里,踩的坑真不少!今天就来说说这个关于组件的周期,说的可能不是很清楚,但是也给自己留下一个踩坑的纪念,如有不妥 还望大家指点一二 Warning: setState(... ...

  10. c++ 调用dl里的导出类

    来源:http://blog.csdn.net/yysdsyl/article/details/2626033 动态dll的类导出:CPPDll2->test.h #pragma once // ...