在《数据集DataSet数据管理(DataAdapter查询更新数据库)》一文中提到可以使用OleDbDataAdapter对象的Update方法还可将对 DataSet 所做的更改解析回数据源,实例化OleDbDataAdapter对象时必须设置InsertCommand、 UpdateCommand或 DeleteCommand属性。那么OleDbDataAdapter对象是如何知道DataSet 数据集中哪些数据是要插入的、哪些是更改过的、而哪些又是需要删除的呢?
ADO.NET 用行状态和行版本管理表中的行。 行状态指示行的状态;行版本在修改行中存储的值时维护各个阶段的值,包括当前值、原始值和默认值。

一、行状态

(一)、RowState枚举

每个 DataRow 对象都具有 RowState 属性,您可以检查此属性来确定行的当前状态。只要该行中某一个字段发生改变,那么这一行对应的RowState属性就会发生改变。RowState是一个枚举,其中包含5个内容:

1、Unchanged

自上次调用 AcceptChanges 以来或由 DataAdapter.Fill 创建该行以来,没有进行任何更改。——原来的行!

2、Added

已将该行添加到表中,但尚未调用 AcceptChanges。——插入的新行!

3、Modified

已更改了行的某个元素。——刚被修改过的行!

4、Deleted

已从表中删除该行,并且尚未调用 AcceptChanges。——刚被删除的行(注意:这里只是从内存表中删除,准确的说是该行只是被做了Deleted标志并没有真的删除,物理数据表中更是没有删除,所以此时你无法直接去访问该行的某个字段的内容!)。

5、Detached

该行不是表中的行——该行不是任何 DataRowCollection 的一部分。 新创建的行、或者已经被Remove或者RemoveAt、或者Delete之后调用过AcceptChanges方法的行、或者是WinForm控件DataGridView默认设置下最后那个永远也留出的空行……都被自动设置该状态。这种状态表示已初始化但未添加到DataTable中的数据行,此状态我们不必太关心。

(二)、检测DataTable表行状态

示例代码首先使用DataSet对象的HasChanges属性检测数据集是否有修改过的数据,然后调用GetChanges方法获取已更改的数据行并保存到新的数据表中,最后调用OleDbDataAdapter对象的Update方法更新数据库。

'检查数据是否发生更改If dst.HasChanges ThenDim dtchanges As DataTable = dst.Tables.Add("dtchanges")'将更改的行保存到新数据表中dtchanges = dst.Tables("mytbl").GetChanges'更新数据库adapter.Update(dst, "dtchanges")End If

DataSet对象GetChanges方法还可以带参数,从而可以获取更具体的被修改过的数据行。如:

            '获取修改过的行dtchanges = dst.Tables("mytbl").GetChanges(DataRowState.Modified)'获取新添加的行dtchanges = dst.Tables("mytbl").GetChanges(DataRowState.Added)'获取已删除的行dtchanges = dst.Tables("mytbl").GetChanges(DataRowState.Deleted)

(三)、接受或拒绝对数据集中数据的更改

对数据集中的数据进更改后,可以使用DataSet对象的AcceptChanges方法接受更改或RejectChanges方法拒绝更改。如:

        '检查数据是否发生更改If dst.HasChanges ThenDim dtchanges As DataTable = dst.Tables.Add("dtchanges")'将更改的行保存到新数据表中dtchanges = dst.Tables("mytbl").GetChanges'检查发生更改的行中是否包含错误If dtchanges.HasErrors() Then'拒绝对数据集所做的更改dst.RejectChanges()Else'更新数据库(注意这句必须在前)adapter.Update(dst, "dtchanges")'接受对数据集所做的更改dst.AcceptChanges()End IfEnd If

你还可以使用带参数的HasChanges方法检查是否有相应的 RowState 的 DataRow 。
在使用OleDbDataAdapter对象的Update方法时,将会检查DataTable中每一行的状态,然后调用相应的InsertCommand、 UpdateCommand或 DeleteCommand命令语句对数据库进行更新。
特别注意, 最终的操作效果其实决定于OleDbDataAdapter 的 SelectCommand、UpdateCommand 或 DeleteCommand命令语句的SQL文本。如果在 UpdateCommand 中写入 Delete 语句,那么状态为 Modified 的 DataRow 最终将在数据库中删除而不是更新。

二、行版本

通过DataRow的RowState属性可以判断哪一行是新插入的,哪一行是被修改过或哪一行已经被删除了,但在调用OleDbDataAdapter对象的Update方法更新数据库时不仅需要获取被修改过后的数据,还需要知道调用OleDbDataAdapter对象Fill方法从数据库填充数据集的原始数据。这就有赖于DataColumn对象的DataRowVersion属性(行版本)。以下提供了对每个 DataRowVersion 枚举值的简短说明。
Current:行的当前值。 如果行的 RowState 属性为 Deleted,则不存在此行版本。
Default:特定行的默认行版本。 Added、Modified 或 Deleted 行的默认行版本是 Current。 Detached 行的默认行版本是 Proposed。
Original:行的原始值。 如果行的 RowState 属性为 Added,则不存在此行版本。
Proposed:行的建议值。 在对行进行编辑操作的过程中,或者对于不属于 DataRowCollection 的行,存在此行版本。
对于新添加的行只有一个版本,而对于修改过的行或已删除的行则需要用主键或唯一约束列的原始值(Original)去跟数据库比对,从而确定要更新或删除的行。
如:

        '添加delete命令参数Dim deletecmd As New OleDbCommand("Delete * FROM stutbl Where ID=?", conn)deletecmd.Parameters.Add("@ID", OleDbType.BigInt, Nothing, "ID").SourceVersion = DataRowVersion.Original'这里需要用原始值adapter.DeleteCommand = deletecmd

通过DataRow的Item(列名或列号)属性来访问行的当前值(Current),而通过DataRow的Item(列名或列号,行版本)属性来访问指定版本的数据。

三、一些理解

1、使用 DataTable.Rows.Add方法添加的 DataRow ,在未接受AcceptChanges()方法前,行状态都为Added。
2、从数据库中查询并通过OleDbDataAdapter.Fill()方法填充的DataTable,如果 DataAdapter.AcceptChangesDuringFill 属性为 true,其所有行的状态都为Unchanged,否则为 Added,默认 AcceptChangesDuringFill 为 true。
3、对于状态为 Unchanged 或者 Modified 的 DataRow,,修改数据后的状态为 Modified;对于状态为 Added 的 DataRow,修改数据后仍然为 Added;如果 DataAdapter.AcceptChangesDuringUpdate 属性为 true,使用 DataAdapter.Update 更新后的DataRow 的状态为 Unchanged,,否则DataRow 的状态保持不变, 默认 AcceptChangesDuringUpdate 为 true;对于状态为 Unchanged 的 DataRow, 调用 Delete 方法后状态为 Deleted;对于状态为 Added 的 DataRow,调用 Delete 方法后状态为 Detached;使用 DataTable.Rows.Remove 方法移除 DataRow 后,DataRow 状态为 Detached。
可见,DataRow对象的Delete方法并未真正移除DataRow(除非此行原状态为Added),而只是将行状态变成了Deleted,并“移除”了它的Current版本。这样,当使用OleDbDataAdapter的Update()进行更新时,其内部机制可以根据仍然存在的Original版本数据,为OleDbDeleteCommand填充参数,完成更新数据库的操作。
而DataRow对象的Remove、Clear方法将彻底地移除行,这种情况下无法生成可执行的OleDbDeleteCommand,也就是说,使用OleDbDataAdapter的Update方法时,并不能像你预想的那样将对应的数据库表数据删除。
4、对 DataSet 或 DataTable 调用AcceptChanges方法时,会移除行状态为 Deleted 的所有行。 剩余行的行状态为 Unchanged,并且 Original 行版本中的值将被 Current 行版本值覆盖。 调用 RejectChanges 时,会移除行状态为 Added 的所有行。 剩余行的行状态为 Unchanged,并且 Current 行版本中的值将被 Original 行版本值覆盖。
特别注意:对 DataSet 、 DataTable或DataRow 调用AcceptChanges方法并不会更改数据库,他只是对数据集中的数据产生作用,与数据库真正相关的是OleDbDataAdapter.Update()方法,它是真正负责执行相关SQL命令的地方。所以你决定要更新数据库必须先使用OleDbDataAdapter.Update()方法,然后才能调用AcceptChanges方法,如果搞反了则不会将更改写回数据库。这两个方法的顺序一定要慎重考虑。
5、行状态为 Unchanged、Modified、Deleted 的 DataRow,使用 DataRow.RejectChanges 方法,行状态将转化为 Unchanged;行状态为 Added、Detached 的 DataRow,使用 DataRow.RejectChanges 方法,行状态将转化为 Detached。
6、 对状态为 Unchanged 的 DataRow,可以使用 DataRow.SetAdded、DataRow.SetModified 方法使行状态转化为 Added 或者 Modified。
注意:SetAdded、SetModified 方法对状态不是 Unchanged 的 DataRow 使用将抛出异常。
7、使用 DataTable.ImportRow 方法导入 DataRow 后,导入的 DataRow 和原 DataRow 的行状态一致。
注意:ImportRow 方法采用复制的方式导入 DataRow,状态为 Detached 的 DataRow,无法导入到 DataTable,但不会产生异常。
8、使用 DataTable.Copy 或者 DataSet.Copy 方法,DataRow 的行状态保持不变。

VB.NET学习笔记:ADO.NET操作ACCESS数据库——OleDbDataAdapter的Update方法更新数据库的秘密(行状态RowState和行版本 DataRowVersion)相关推荐

  1. VB.NET学习笔记:ADO.NET操作ACCESS数据库——ADO.NET数据访问接口

    一.ADO.NET概述 Ado.net基于XML和离线计算模型. ADO.net的两个核心组件:.Net数据提供程序.DataSet. .net数据提供程序用来与数据库的连接,如SQLServer.n ...

  2. tensorflow学习笔记——使用TensorFlow操作MNIST数据(1)

    续集请点击我:tensorflow学习笔记--使用TensorFlow操作MNIST数据(2) 本节开始学习使用tensorflow教程,当然从最简单的MNIST开始.这怎么说呢,就好比编程入门有He ...

  3. jQuery学习笔记之DOM操作、事件绑定(2)

    jQuery学习笔记之DOM操作.事件绑定(2) --------------------学习目录------------------------ 4.DOM操作 5.事件绑定 源码地址: https ...

  4. NetLogo学习笔记3 —— 集合操作与生命游戏

    NetLogo学习笔记3 -- 集合操作与生命游戏 (这篇新知识点略多) 上一篇文章我们了解NetLogo模型的基本要素,学习了函数定义与ask语法.并编写了我们的第一个程序! 这一次,我们来编写一个 ...

  5. c# 学习笔记 (2) 窗体之间互相调用的方法

    c# 学习笔记 (2) 窗体之间互相调用的方法 创建一个winform工程 创建两个窗体 一个子窗体,一个父窗体,这里为了演示,子窗体和父窗体上都有一个文本框和按键,点击任意一个窗体上的按键,窗体上文 ...

  6. Oracle中用system存数据,【学习笔记】Oracle表空间 数据存放system表空间影响数据库性能...

    天萃荷净 分享一篇,关于Oracle数据库system表空间研究,不能将用户数据存放在system表空间的原因 为什么不建议客户把业务数据存放到SYSTEM表空间中,一直想通过试验的数据来说明问题,今 ...

  7. Unity Shader 学习笔记(27)渲染轮廓线(描边)方法、卡通风格渲染、素描风格渲染

    Unity Shader 学习笔记(27)渲染轮廓线(描边)方法.卡通风格渲染.素描风格渲染 参考书籍:<Unity Shader 入门精要> 渲染轮廓线(描边) 五种方法: 基于观察角度 ...

  8. OpenCV学习笔记(二十一)——绘图函数core OpenCV学习笔记(二十二)——粒子滤波跟踪方法 OpenCV学习笔记(二十三)——OpenCV的GUI之凤凰涅槃Qt OpenCV学习笔记(二十

    OpenCV学习笔记(二十一)--绘图函数core 在图像中,我们经常想要在图像中做一些标识记号,这就需要绘图函数.OpenCV虽然没有太优秀的GUI,但在绘图方面还是做得很完整的.这里就介绍一下相关 ...

  9. hpux安装oracle数据库,【学习笔记】HP-UNIX系统安装BUNDLE和补丁包的方法步骤

    天萃荷净 Oracle研究中心学习笔记:分享一篇关于HP-UNIX系统安装系统安装BUNDLE和补丁包的方法步骤. HPUX补丁包分2种: 1.BUNDLE在一起的: 2.单个的小补丁: 如果补丁包B ...

最新文章

  1. sqlserver 编辑、修改字段说明(备注) sp_addextendedproperty
  2. 算法工程师和算法框架开发,谁会代表未来?
  3. 【学习笔记】25、关系数据库存储
  4. 42、Power Query-Text.Remove函数应用
  5. 入选《2021爱分析·区域性银行数字化厂商全景报告》,网易云信助力南京银行打造转型标杆
  6. Protobuf序列化的原理-总结
  7. 拔号×××与站点×××的配置
  8. oracle client 11.2.0.3 32位,oracle client 32位/64位下载(Oracl数据库)
  9. input子系统基础之按键4——输入核心层源码分析
  10. mfc控件位置随对话框窗口移动
  11. exit和abort都是用来终止程序的函数
  12. MediaCodec 编码时间戳问题
  13. JUnit5 @BeforeAll注解示例
  14. 美研计算机案例,美国研究生申请案例:耶鲁大学录取:计算机硕士【2010】
  15. 辨异 —— 数学基本概念
  16. 返回List的分页方法
  17. 7-7 mmh学长的大数模板 (20分)
  18. TwinCAT3中台达A2增量编码器伺服使用PDO方式回零
  19. 学c语言前要了解什么软件,学习c语言需要什么软件?
  20. QT的Q3DScatter使用(三维可视图)

热门文章

  1. Linux中sudo,su与su -命令的区别
  2. 浅谈Visual C#进行图像处理
  3. matlab griddata插值太慢,非常慢的插值使用`scipy.interpolate.griddata`
  4. 【Win11】重装系统详细教程
  5. linux fvwm作用_使用FVWM自定义Linux桌面
  6. 是c语言正确常量的是_,下列表达中,是C语言正确常量的是________。
  7. 华北科技学院 嵌入式实训知识点
  8. Intel HAXM is required to run this AVD. Virtual machine acceleration driver is out-of-date
  9. 【网络安全】CmsEasy 漏洞挖掘
  10. 基于于唐都实验箱的多功能电子琴