本文共 5418 字,大约阅读时间需要 18 分钟。
在《》一文中提到可以使用OleDbDataAdapter对象的Update方法还可将对 DataSet 所做的更改解析回数据源,实例化OleDbDataAdapter对象时必须设置InsertCommand、 UpdateCommand或 DeleteCommand属性。那么OleDbDataAdapter对象是如何知道DataSet 数据集中哪些数据是要插入的、哪些是更改过的、而哪些又是需要删除的呢?
用行状态和行版本管理表中的行。 行状态指示行的状态;行版本在修改行中存储的值时维护各个阶段的值,包括当前值、原始值和默认值。一、行状态
(一)、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 Then Dim 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 Then Dim 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 If End 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 的行状态保持不变。转载地址:https://blog.csdn.net/zyjq52uys/article/details/88948594 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!