验证 .NET Framework 应用程序中数据集中的数据

注释

此类 DataSet 和相关类是 2000 年代初的旧版 .NET Framework 技术,使应用程序能够在应用与数据库断开连接时处理内存中的数据。 这些技术对于使用户能够修改数据并将更改保留回数据库的应用特别有用。 尽管数据集是经过证实的成功技术,但新 .NET 应用程序的建议方法是使用 Entity Framework Core。 Entity Framework 提供了一种更自然的方式来将表格数据用作对象模型,并且具有更简单的编程接口。

验证数据是确认在数据对象中输入的值符合数据集架构中的约束的过程。 验证过程还确认这些值遵循为应用程序建立的规则。 在向基础数据库发送更新之前,最好先验证数据。 这可减少错误以及应用程序与数据库之间可能的往返次数。

可以通过在数据集本身中生成验证检查来确认写入数据集的数据是否有效。 无论更新的执行方式如何,数据集都可以检查数据,无论是直接通过窗体中的控件、组件内部还是以其他方式执行。 由于数据集是应用程序的一部分(与数据库后端不同),因此它是生成特定于应用程序的验证的逻辑位置。

向应用程序添加验证的最佳位置是在数据集的分部类文件中。 在 Visual Basic 或 Visual C# 中,打开 数据集设计器 ,然后双击要为其创建验证的列或表。 此作将打开代码文件,可在其中创建 ColumnChangingRowChanging 事件处理程序。

private static void OnColumnChanging(object sender, DataColumnChangeEventArgs e)
{

}

验证数据

数据集中的验证通过以下方式完成:

DataTable 对象中某个记录发生更改时,会触发多个事件:

  • 每次更改单个列时和更改之后都会引发 ColumnChangingColumnChanged 事件。 如果要验证特定列中的更改,该 ColumnChanging 事件非常有用。 有关建议的更改的信息将作为参数传递到事件。
  • 行中发生任何更改时和更改后,将引发 RowChangingRowChanged 事件。 事件 RowChanging 更为常规。 它指示更改发生在行中的某个位置,但不知道哪个列已更改。

默认情况下,对列的每个更改都会引发四个事件。 首先是更改的特定列的 ColumnChangingColumnChanged 事件。 接下来是 RowChangingRowChanged 事件。 如果对行进行了多项更改,则每次发生更改时都会引发事这些件。

注释

数据行 BeginEdit 的方法在每个列更改后关闭 RowChangingRowChanged 事件。 在这种情况下,只有在调用EndEdit方法之后,RowChangingRowChanged事件才会被引发,并且这些事件仅会被触发一次。 有关详细信息,请参阅 在填充数据集时关闭约束

事件的选择取决于您希望验证达到多细的程度。 如果在列发生更改时立即捕获错误很重要,请使用 ColumnChanging 事件生成验证。 否则,请使用 RowChanging 事件,这可能会一次捕获多个错误。 此外,如果数据是结构化的,以便根据另一列的内容验证一列的值,请在 RowChanging 事件期间执行验证。

当记录更新时,DataTable 对象会触发事件,使您可以在更改发生时以及更改完成后做出响应。

如果应用程序使用类型化数据集,则可以创建强类型事件处理程序。 这将添加四个可为其创建处理程序的附加类型事件: dataTableNameRowChangingdataTableNameRowChangeddataTableNameRowDeletingdataTableNameRowDeleted。 这些类型化的事件处理程序传递一个参数,该参数包含表的列名,使代码更易于编写和读取。

数据更新事件

事件 DESCRIPTION
ColumnChanging 正在更改列中的值。 事件向你传递行和列以及建议的新值。
ColumnChanged 列中的值已更改。 事件向你传递行和列以及建议的值。
RowChanging DataRow 对象所做的更改即将提交回数据集。 如果尚未调用 BeginEdit 方法,则会在 ColumnChanging 事件引发后,立即针对列的每次更改引发 RowChanging 事件。 如果在进行更改之前调用了 BeginEdit ,则仅当调用 EndEdit 方法时才会引发 RowChanging 事件。

事件将行传递给你,并提供一个值,该值指示正在执行的操作类型(更改、插入等)。
RowChanged 已更改行。 事件将行传递给你,并提供一个值,该值指示正在执行的操作类型(更改、插入等)。
RowDeleting 正在删除行。 事件将行传递给你,并提供一个值,该值指示正在执行的操作类型(删除)。
RowDeleted 一行已被删除。 事件将行传递给你,并提供一个值,该值指示正在执行的操作类型(删除)。

在更新过程中,会引发ColumnChangingRowChangingRowDeleting事件。 可以使用这些事件来验证数据或执行其他类型的处理。 由于更新在这些事件期间正在进行中,因此可以通过引发异常来取消更新,从而阻止更新完成。

ColumnChangedRowChangedRowDeleted事件是更新成功完成时引发的通知事件。 在根据成功的更新采取进一步的操作时,这些事件非常有用。

在列更改过程中验证数据

注释

数据集设计器创建一个分部类,可在其中将验证逻辑添加到数据集。 设计器生成的数据集不会删除或更改分部类中的任何代码。

可以通过响应 ColumnChanging 事件来验证数据列中的值发生更改时的数据。 引发时,此事件将传递一个包含当前列建议的值的事件参数 (ProposedValue)。 根据e.ProposedValue的内容,您可以:

  • 通过不执行任何操作来接受所建议的值。

  • 从更改列的事件处理程序中设置列错误 (SetColumnError)以拒绝建议的值。

  • (可选)使用 ErrorProvider 控件向用户显示错误消息。 有关详细信息,请参阅 ErrorProvider 组件

还可以在 RowChanging 事件期间执行验证。

在行更改过程中验证数据

可以编写代码来验证要验证的每个列是否包含满足应用程序要求的数据。 设置列,使其在建议的值不可接受时包含错误,以完成此操作。 下面的示例在 Quantity 列等于或小于 0 时设置列错误。 更改行的事件处理程序应类似于以下示例。

在行更改时验证数据(Visual Basic)

  1. 数据集设计器中打开数据集。 有关详细信息,请参阅 演练:在数据集设计器中创建数据集

  2. 双击要验证的表的标题栏。 此操作会在数据集的分部类文件中自动创建 DataTableRowChanging 事件处理程序。

    小窍门

    双击表名左侧以创建行更改事件处理程序。 如果双击表名称,可以对其进行编辑。

    Private Sub Order_DetailsDataTable_Order_DetailsRowChanging(
        ByVal sender As System.Object, 
        ByVal e As Order_DetailsRowChangeEvent
      ) Handles Me.Order_DetailsRowChanging
    
        If CType(e.Row.Quantity, Short) <= 0 Then
            e.Row.SetColumnError("Quantity", "Quantity must be greater than 0")
        Else
            e.Row.SetColumnError("Quantity", "")
        End If
    End Sub
    

在行更改时验证数据 (C#)

  1. 数据集设计器中打开数据集。 有关详细信息,请参阅 演练:在数据集设计器中创建数据集

  2. 双击要验证的表的标题栏。 该操作为DataTable创建一个分部类文件。

    注释

    数据集设计器不会自动为RowChanging事件创建事件处理程序。 必须创建一个方法来处理 RowChanging 事件,并运行代码来挂钩表的初始化方法中的事件。

  3. 将以下代码复制到分部类中:

    public override void EndInit()
    {
        base.EndInit();
        Order_DetailsRowChanging += TestRowChangeEvent;
    }
    
    public void TestRowChangeEvent(object sender, Order_DetailsRowChangeEvent e)
    {
        if ((short)e.Row.Quantity <= 0)
        {
            e.Row.SetColumnError("Quantity", "Quantity must be greater than 0");
        }
        else
        {
            e.Row.SetColumnError("Quantity", "");
        }
    }
    

检索已更改的行

数据表中的每个行都有一个 RowState 属性,该属性使用枚举中的值跟踪该行的 DataRowState 当前状态。 可以通过调用 DataSetDataTableGetChanges 方法,从数据集或数据表返回已更改的行。 可以通过调用数据集的HasChanges方法来验证在调用GetChanges之前是否存在更改。

注释

提交对数据集或数据表的更改(通过调用 AcceptChanges 该方法)后,该方法 GetChanges 不返回任何数据。 如果应用程序需要处理更改的行,则必须在调用 AcceptChanges 该方法之前处理更改。

GetChanges调用数据集或数据表的方法返回仅包含已更改记录的新数据集或数据表。 如果要获取特定记录(例如,仅新记录或仅修改的记录),则可以将 DataRowState 枚举中的值作为参数传递给 GetChanges 方法。

使用 DataRowVersion 枚举访问行的不同版本(例如,处理行之前行的原始值)。

从数据集获取所有已更改记录

  • 调用数据集的GetChanges方法。

    以下示例创建一个调用 changedRecords 的新数据集,并使用另一个调用 dataSet1的数据集中的所有已更改记录填充该数据集。

    DataSet changedRecords = dataSet1.GetChanges();
    

从数据表中获取所有已更改的记录

  • 调用 DataTable 的 GetChanges 方法。

    以下示例创建一个调用 changedRecordsTable 的新数据表,并使用另一个调用 dataTable1的数据表中的所有已更改记录进行填充。

    DataTable changedRecordsTable = dataTable1.GetChanges();
    

获取具有特定行状态的所有记录

  • 调用数据集或数据表的GetChanges方法,并将DataRowState枚举值作为参数传递。

    以下示例演示如何创建一 addedRecords 个名为的新数据集,并仅使用已添加到数据集的 dataSet1 记录填充该数据集。

    DataSet addedRecords = dataSet1.GetChanges(DataRowState.Added);
    

    以下示例演示如何返回最近添加到 Customers 表的所有记录:

    private NorthwindDataSet.CustomersDataTable GetNewRecords()
    {
        return (NorthwindDataSet.CustomersDataTable)
            northwindDataSet1.Customers.GetChanges(DataRowState.Added);
    }
    

访问 DataRow 的原始版本

对数据行进行更改时,数据集将保留行的原始版本(Original)和新版本。Current 例如,在调用 AcceptChanges 该方法之前,应用程序可以访问记录的不同版本(如枚举中 DataRowVersion 定义),并相应地处理更改。

注释

仅当该行已被编辑且在调用 AcceptChanges 方法之前,才会有不同的版本存在。 AcceptChanges调用该方法后,当前版本和原始版本相同。

DataRowVersion 值与列索引(或列名称作为字符串)一起传递将返回该列的特定行版本中的值。 更改后的列在ColumnChangingColumnChanged事件期间被标识。 这是检查不同行版本以进行验证的好时机。 但是,如果你暂时挂起了约束,则不会引发这些事件,将需要以编程方式标识哪些列已更改。 可以通过循环访问 Columns 集合并比较不同的 DataRowVersion 值来执行此作。

获取记录的原始版本

  • 通过传入要返回的行的 DataRowVersion 来访问列的值。

    以下示例演示如何使用DataRowVersion值获取DataRowCompanyName字段的原始值:

    string originalCompanyName;
    originalCompanyName = northwindDataSet1.Customers[0]
        ["CompanyName", DataRowVersion.Original].ToString();
    

访问 DataRow 的当前版本

获取记录的当前版本

  • 访问列的值,然后将参数添加到索引中,该索引指示要返回的行的版本。

    以下示例演示如何使用DataRowVersion值来获取DataRowCompanyName字段的当前值:

    string currentCompanyName;
    currentCompanyName = northwindDataSet1.Customers[0]
        ["CompanyName", DataRowVersion.Current].ToString();