这个属性是一个只读属性的枚举类型,一共有五个值,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. Lottie安卓开源动画库使用

    碉堡的Lottie Airbnb最近开源了一个名叫Lottie的动画库,它能够同时支持iOS,Android与ReactNative的开发.此消息一出,还在苦于探索自定义控件各种炫酷特效的我,兴奋地就 ...

  2. matlab最简单程序模板

    % 脚本文件: 温度转换 % 文件名:temp_conversion % 目标:将输入的华氏温度转换为绝对温度 % % 版本记录: % 时间 编者 描述 % -- :: 泡泡 原始代码 % % 定义变 ...

  3. Redis 学习之事务处理

    Redis事务机制 在MySQL等其他数据库中,事务表示的是一组动作,这组动作要么全部执行,要么全部不执行. Redis目前对事物的支持相对简单.Redis只能保证一个client发起的事务中的命令可 ...

  4. java学习笔记——IO流部分

    IO流常用的有:字符流.字节流.缓冲流.序列化.RandomAccessFile类等,以上列出的都是开发中比较常用的. 1.字节流: 字节流包含:FileInputStream/FileOutputS ...

  5. cura-engine学习(1)

    cura-engine为开源3D打印软件cura的核心引擎代码,详细介绍参看github主页.现在学习的是一个简单版的https://github.com/repetier/CuraEngine,最新 ...

  6. Kettle 5.0源码编译

    下载源码请参考上一篇博文Kettle4.4.2源码分析 Kettle 5.0以前的库文件通过ant管理,5.0+的库文件通过ant+ivy管理.Eclipse一般都是安装ant插件,不安装ivy插件, ...

  7. 第八讲:I/O虚拟化

    一.I/O虚拟化的产生 服务器单个千兆以太网端口肯定能够支持单个应用,但是当被分割为10个.15个或者更多的服务器负载时(这其中包括网络.存储以及服务器之间的流量)可能就不够用了. 当遇到I/O瓶颈时 ...

  8. 每天一个linux命令(42)--traceroute命令

    通过traceroute 我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不 ...

  9. 条件查询php

    页面1.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...

  10. 第十六篇 基于Bootstarp 仿京东多条件筛选插件的开发(展示上)

    这几天学习Bootstrap,本来是两年前的用的东西,现在又重新拾起来,又有很多重新的认识,看了Bootstrap的样式偏多,插件现在还没有学习到几个,也有写几个插件自己用的想法.正好工作上也会用到, ...