数据集更新介绍(来自MSDN)

因为数据集是有效的数据缓存(数据在内存中的副本),所以将信息写入初始数据源的进程与在数据集中修改数据的进程是分开的。

注意在某些情况下,您可能根本就不使用数据集。通过调用 SQL 语句或存储过程并向其传递更新信息,可以将更新直接发送到数据源(通常是数据库)。有关直接与数据源通信的更多信息,请参见 Visual Studio 中的 DataCommand 对象介绍

两步更新

通过数据集更新数据源是一个包含两个步骤的过程。第一步是使用新信息(新记录、已更改的记录或已删除的记录)更新数据集。如果您的应用程序只与数据集有关(例如在更新数据集后,将其发送给另一个应用程序,由它对数据集执行进一步处理),那么您就完成了更新。

注意在 Windows 窗体中,数据绑定结构负责将更改从数据绑定控件发送到数据集,您不必用自己的代码显式更新数据集。有关更多信息,请参见 Windows 窗体数据结构

如果您正在更新数据源(如数据库),第二步则是将更改从数据集发送到初始数据源。也就是说,更新数据集的过程不会同时将更改直接写入基础数据源,所以您必须显式执行第二步。为了完成这一步骤,您通常会调用曾用来填充数据集的同一个数据适配器的 Update 方法(虽然您也可以使用不同的适配器,例如为了将数据从一个数据源移动到另一个数据源或更新多个数据源)。

两步更新过程和 DataRowVersion 在成功更新中的作用

有关如何将更改从数据集传送到数据库的更多信息,请参见从数据集更新数据库

在结构上,数据集使数据可以作为多组集合来使用。数据集包含表的集合。表包含行的集合。表公开为 DataSet 对象的集合,而记录在 DataTable 对象的 Rows 集合中可用。您可以通过使用基集合方法操作这些集合来对数据集中的数据进行更改,但是如果您要更新基础数据源,则必须使用专用于数据集修改的方法。

例如,要从数据表中移除一个记录,可以调用该表的 Rows 集合的 RemoveAt Method,它会从数据集中实际删除该记录。如果您只是将数据集用作数据的结构化存储区,而不考虑将更改信息传送到另一个应用程序,那么以这种方式操作集合就是一种可以接受的数据集更新方式。

但是,如果您要将更改发送到数据源或另一个应用程序,则需要维护有关每次更新的更改信息(即元数据)。随后,在将更改发送到数据源或应用程序时,该过程将使用它所需的信息来查找和更新适当的记录。例如,如果您删除数据集中的一个记录,则应该在数据集中维护有关该删除记录的信息,这样当调用数据适配器的 DeleteCommand 时,将会有足够的历史信息来查找数据源中的初始记录,从而将其删除。有关更多信息,请参见下面的“维护有关更改的信息”。有关更多信息,请参见在数据集中更新、插入和删除记录

合并数据集

您可以通过合并来更新数据集的内容,合并就是将称作“源”的数据集的内容复制到调用数据集(称作“目标”数据集)中。当合并数据集时,源数据集中的新记录将添加到目标数据集中。另外,源数据集中额外的列也会添加到目标数据集中。当您具有一个本地数据集然后又从另一个应用程序或组件(如 XML Web services)获得另外一个数据集,或者只是需要集成来自多个数据集中的数据时,合并数据集就会特别有用。

当合并数据集时,还可以传递一个可选的 Boolean 参数 (preserveChanges),它指示 Merge 方法是否在目标数据集中保留现有的修改。由于数据集维护记录的多个版本,所以务必要记住所合并的是记录的多个版本。下表阐释了将要合并的两个数据集中的一个记录:

DataRowVersion 目标数据集 源数据集
Original James Wilson James C. Wilson
Current Jim Wilson James C. Wilson

preserveChanges=false targetDataset.Merge(sourceDataset) 的情况下,在上表调用 Merge 方法将产生以下结果:

DataRowVersion 目标数据集 源数据集
Original James C. Wilson James C. Wilson
Current James C. Wilson James C. Wilson

preserveChanges = true targetDataset.Merge(sourceDataset, true) 的情况下调用 Merge 方法将产生以下结果:

DataRowVersion 目标数据集 源数据集
Original James C. Wilson James C. Wilson
Current Jim Wilson James C. Wilson
警告preserveChanges=true 情况下,如果对目标数据集中的记录调用 RejectChanges 方法,它将还原为“源”数据集中的初始数据。这意味着如果您要用目标数据集更新初始数据源,则可能无法找到要更新的初始行。但是,在并发冲突的情况(即另一个用户在数据集被填充后修改数据源中的记录)下,通过用数据源中已更新的记录填充另一个数据集,然后执行合并,可以防止出现并发冲突。有关更多信息,请参见 ADO.NET 中的并发控制合并数据集

更新约束

要对现有的数据行进行更改,可以在个别列中添加或更新数据。如果数据集包含约束(例如外键或不可为空的约束),那么当您更新记录时(在更新完一列之后,但在开始更新下一列之前),记录可能会暂时处于错误状态。

为了避免这种早产的约束冲突,可以暂时挂起更新约束。这可达到两个目的:

  • 防止在更新完一列后,开始更新另一列之前引发错误。
  • 暂停引发某些更新事件(常用于冲突的事件)。

完成更新后,可以重新启用约束检查,约束检查还重新启用更新事件并引发它们。

注意在 Windows 窗体中,内置在数据网格中的数据绑定结构会暂停约束检查,直到焦点移出行外为止,因此您不必显式调用 BeginEditEndEditCancelEdit 方法。

当对数据集调用 Merge 方法时,将自动禁用约束。当合并完成后,如果数据集上有任何无法启用的约束,则引发 ConstraintException。在这种情况下,EnforceConstraints 属性将设置为 false,在将 EnforceConstraints 属性重新设置为 true 之前,必须解决所有的约束冲突。

完成更新后,可以重新启用约束检查,约束检查还重新启用更新事件并引发它们。

有关暂停事件的更多信息,请参见暂停更新约束。有关事件的更多信息,请参见数据更新事件

数据集更新错误

当更新数据集中的记录时,可能出现错误。例如,您可能在无意中将数据类型错误、太长或具有某些其他完整性问题的数据写入一个列中。此外,您可能拥有应用程序特定的验证检查,它们可在更新事件的任何阶段引发自定义的错误。有关更多信息,请参见数据集中的数据验证

维护有关更改的信息

有关数据集中更改的信息可以通过以下两种方式来进行维护:通过对行作出标记,指示该行是否已更改 (RowState);以及通过保留记录的多个副本 (DataRowVersion)。利用这些更改信息,进程可以确定数据集中有哪些更改,并且可以将适当的更新发送到数据源。

RowState 属性

DataRow 对象的 RowState 属性是一个值,它提供有关特定数据行状态的信息。

下表详细说明 DataRowState 枚举的可能值:

DataRowState 值 说明
Added 该行已作为一项添加到 DataRowCollection。(处于这种状态的行不具有相应的初始版本,因为在最近一次调用 AcceptChanges 方法时它尚不存在)。
Deleted 已使用 DataRow 对象的 DataRow.Delete 方法删除该行。
Detached 已创建该行,但它不是任何 DataRowCollection 的一部分。在 DataRow 对象刚创建之后但在添加到集合之前,或者如果该对象已从集合中移除,它将处于这种状态。
Modified 该行中的列值已通过某种方式更改。
Unchanged 自上一次调用 AcceptChanges 之后,该行未更改。

DataRowVersion 枚举

数据集维护记录的多个版本。DataRow 对象的 DataRowVersion 枚举是一个值,它可用于返回 DataRow 对象的特定版本。

下表详细说明了 DataRowVersion 枚举的可能值:

DataRowVersion 值 说明
Current 记录的当前版本包含自上次调用 AcceptChanges 后对记录执行的所有修改。如果该行已被删除,则没有当前版本。
Default 记录的默认值,如数据集架构或数据源所定义的一样。
Original 记录的初始版本是在数据集中最后一次提交更改时记录的副本。实际上,它通常是从数据源中读取的记录版本。
Proposed 更新过程当中(即在调用 BeginEdit 方法和调用 EndEdit 方法之间)临时可用的记录的建议版本。通常在事件(例如 RowChanging)处理程序中访问记录的建议版本。调用 CancelEdit 方法将撤消更改并删除数据行的建议版本。

当更新信息传送到数据源时,初始版本和当前版本十分有用。通常,当更新被发送到数据源时,数据库的新信息处于记录的当前版本,而来自初始版本的信息则用于查找要更新的记录。例如,在更改了记录主键的情况下,为了将该更改更新到数据源,必须通过某种方式在数据源中查找适当的记录。如果不存在初始版本,很可能会将该记录追加到数据源,这不仅会导致一项额外的多余记录,而且还会导致一条不准确并且已过期的记录。这两个版本也用于并发控制;您可以将初始版本与数据源中的记录进行比较,以确定该记录自加载到数据集之后是否经过更改。有关更多信息,请参见 ADO.NET 中的并发控制

当您需要在将更改实际提交到数据集之前执行验证时,可以使用建议版本。

即使记录已更改,也不总会有该行的初始版本或当前版本。当您将新行插入表中时,没有初始版本,只有当前版本。同样,如果通过调用表的 Delete 方法删除一行,则只有初始版本,没有当前版本。

可以通过查询数据行的 HasVersion 属性来测试记录的某个特定版本是否存在。当请求列的值时,通过将 DataRowVersion 枚举值作为可选参数进行传递,可以访问记录的任何一个版本。

获取已更改的记录

通常,不会对数据集中的每个记录进行更新。例如,用户可能正在处理一个显示很多记录的 Windows 窗体 DataGrid 控件。但是,用户可能只更新了几个记录,删除了一个记录,并插入了一个新记录。数据集和数据表提供了一种只返回已修改行的方法 (GetChanges)。

可以使用数据表的 GetChanges 方法 (DataTable.GetChanges) 或数据集本身的 GetChanges 方法 (DataSet.GetChanges) 来创建已更改记录的子集。如果对数据表调用该方法,它将返回只包含已更改记录的数据表副本。同样,如果对数据集调用该方法,将获得一个新的数据集,其中只包含已更改的记录。GetChanges 本身将返回所有已更改的记录,然而,通过将所需的 DataRowState 当作参数传递给 GetChanges 方法,则可以指定所需的更改记录子集:新添加的记录、标记为删除的记录、分离的记录和已修改的记录。

当需要将记录发送给另一个组件进行处理时,获取已更改记录的子集非常有用。通过只获取该组件所需的记录而不是发送整个数据集,可以降低与其他组件通信的系统开销。有关更多信息,请参见检索已更改的行

提交数据集中的更改

当在数据集中作出更改时,即设置了所更改行的 RowState 属性。此时将建立并维护记录的初始版本和当前版本,并通过 RowVersion 属性供您使用。要将适当的更新发送给数据源,需要使用存储在这些属性中表示更改的元数据。

如果更改反映了数据源的当前状态,则不再需要维护该信息。通常,数据集及其数据源在以下两个时间是同步的:

  • 刚刚将信息加载到数据集之后,例如从数据源读取数据时。
  • 将更改从数据集发送到数据源之后(但不是在这之前,因为您可能丢失将更改发送到数据库所需的更改信息)。

通过调用 AcceptChanges 方法,可以将挂起的更改提交到数据集。通常,在以下时间将在应用程序中调用 AcceptChanges

  • 在加载数据集之后。如果通过调用数据适配器的 Fill 方法来加载数据集,数据适配器将自动为您提交更改。但是,如果通过将另一个数据集合并到其中来加载数据集,则需要手动提交更改。
    注意通过将适配器的 AcceptChangesDuringFill 属性设置为 false,可以防止在调用 Fill 方法时数据适配器自动提交更改。如果设置为 false,在填充时插入的每行的 RowState 将设置为 Added
  • 在将数据集更改发送到另一个进程(例如 XML Web services)之后。
    警告以这种方法提交更改会清除所有更改信息。在执行应用程序确信已知在数据集中作出何种更改的任何操作之前,请不要提交更改。

该方法完成以下操作:

  • 将记录的 Current 版本写入其 Original 版本,以改写初始版本。
  • 移除所有 RowState 属性设置为 Deleted 的行。
  • 将记录的 RowState 属性设置为 Unchanged

AcceptChanges 方法可以在三个级别上使用。可以对 DataRow 对象调用该方法,它只提交该行的更改。您还可以对 DataTable 对象调用该方法,以提交表中所有行的更改,或者对 DataSet 对象调用该方法,以提交数据集中所有表的所有记录的所有挂起的更改。

下表基于对何种对象调用该方法说明所提交的更改。

方法 结果
DataRow.AcceptChanges 只提交特定行的更改
DataTable.AcceptChanges 提交特定表中所有行的更改
DataSet.AcceptChanges 提交数据集中所有表的所有行的更改
注意如果通过调用数据适配器的 Fill 方法加载数据集,则无需显式接受更改;默认情况下,Fill 方法会在填充完数据表后调用 AcceptChanges 方法。

相关方法 (RejectChanges) 撤消更改的结果,方法是将记录的 Original 版本复制到 Current 版本中并将每个记录的 RowState 设置回 Unchanged

数据验证

为了验证应用程序中的数据符合它将传递到的进程的要求,通常需要添加验证。这可能会涉及到检查用户在窗体中的输入是否正确,验证另一个应用程序向您的应用程序发送的数据,甚至检查在您的组件中计算的信息是否符合数据源约束和应用程序要求。

您可以通过多种方法验证数据:

  • 在表示层,向窗体添加验证。如果您正在使用 Web 窗体页,则可以为此目的使用验证控件。有关更多信息,请参见 Web 窗体的用户输入验证简介。如果您正在使用 Windows 窗体,则通常将验证与 TextBoxRichTextBox 控件关联。控制用户在 Windows 窗体上的有效输入的另一种方法是 Masked Edit 控件
  • 在数据后端,将数据发送到数据源(例如数据库)并允许它接受或拒绝该数据。如果您正在使用一个数据库,而该数据库具有复杂的功能来验证数据并提供错误信息,则这将是一种实用的方法,因为无论数据来自何处,您都可以对数据进行验证。但是,它可能不适合应用程序特定的验证的需要。另外,根据您的应用程序如何解决由后端引发的验证错误,让数据源验证数据可能导致大量到数据源的往返过程。
    安全说明当使用 CommandType 属性设置为 Text 的数据命令时,请对从客户端发送过来的信息进行仔细检查,然后再将它传递给数据库。恶意用户可能会试图发送(插入)修改过的或其他 SQL 语句,以获得未经授权的访问或破坏数据库。在将用户输入内容传输到数据库之前,应始终确认这些信息是有效的;如果可能的话,请始终使用参数化查询或存储过程,这是最佳措施。有关更多信息,请参见脚本利用
  • 在业务层,将代码添加到应用程序中以便验证数据。数据集是执行此类验证的合适场所。数据集提供了后端验证的某些优点(例如能够验证对数据的更改,而无论这些更改是如何做出的),同时还能提供特定于应用程序的验证。有关更多信息,请参见数据集中的数据验证
阅读更多
想对作者说点什么? 我来说一句

wine数据集

2014年05月16日 11KB 下载

没有更多推荐了,返回首页

关闭
关闭
关闭