Validate data in datasets

 

For the latest documentation on Visual Studio 2017, see Validate data in datasets on docs.microsoft.com. Validating data is the process of confirming that the values being entered into data objects conform to the constraints within a dataset's schema. The validation process also confirms that these values are following the rules that have been established for your application. It's a good practice to validate data prior to sending updates to the underlying database. This reduces errors as well as the potential number of round trips between an application and the database.

You can confirm that data that's being written to a dataset is valid by building validation checks into the dataset itself. The dataset can check the data no matter how the update is being performed — whether directly by controls in a form, within a component, or in some other way. Because the dataset is part of your application (unlike the database backend), it's a logical place to build application-specific validation.

The best place to add validation to your application is in the dataset's partial class file. In Visual Basic or Visual C#, open the Dataset Designer and double-click the column or table for which you want to create validation. This action automatically creates an ColumnChanging or RowChanging event handler. For more information, see How to: Validate Data During Column Changes or How to: Validate Data During Row Changes. For a complete example, see Walkthrough: Adding Validation to a Dataset.

Validation within a dataset can be accomplished in the following ways:

Several events are raised by the DataTable object when a change is occurring in a record:

By default, each change to a column therefore raises four events. The first is the ColumnChanging and ColumnChanged events for the specific column that's being changed. Next are the RowChanging and RowChanged events. If multiple changes are being made to the row, the events will be raised for each change.

System_CAPS_ICON_note.jpg Note

The data row's BeginEdit method turns off the RowChanging and RowChanged events after each individual column change. In that case, the event is not raised until the EndEdit method has been called, when the RowChanging and RowChanged events are raised just once. For more information, see Turn off constraints while filling a dataset.

The event you choose depends on how granular you want the validation to be. If it's important that you catch an error immediately when a column changes, build validation by using the ColumnChanging event. Otherwise, use the RowChanging event, which might result in catching several errors at once. Additionally, if your data is structured so that the value of one column is validated based on the contents of another column, then perform your validation during the RowChanging event.

When records are updated, the DataTable object raises events that you can respond to as changes are occurring and after changes are made.

If your application uses a typed dataset, you can create strongly typed event handlers. This will add four additional typed events that you can create handlers for: dataTableNameRowChanging, dataTableNameRowChanged, dataTableNameRowDeleting, and dataTableNameRowDeleted. These typed event handlers pass an argument that includes the column names of your table that make code easier to write and read.

EventDescription
ColumnChangingThe value in a column is being changed. The event passes the row and column to you, along with the proposed new value.
ColumnChangedThe value in a column has been changed. The event passes the row and column to you, along with the proposed value.
RowChangingThe changes that were made to a DataRow object are about to be committed back into the dataset. If you have not called the BeginEdit method, the RowChanging event is raised for each change to a column immediately after the ColumnChanging event has been raised. If you called BeginEdit before making changes, the RowChanging event is raised only when you call the EndEdit method.

The event passes the row to you, along with a value indicating what type of action (change, insert, and so on) is being performed.
RowChangedA row has been changed. The event passes the row to you, along with a value indicating what type of action (change, insert, and so on) is being performed.
RowDeletingA row is being deleted. The event passes the row to you, along with a value indicating what type of action (delete) is being performed.
RowDeletedA row has been deleted. The event passes the row to you, along with a value indicating what type of action (delete) is being performed.

The ColumnChanging, RowChanging, and RowDeleting events are raised during the update process. You can use these events to validate data or perform other types of processing. Because the update is in process during these events, you can cancel it by throwing an exception, which prevents the update from finishing.

The ColumnChanged, RowChanged and RowDeleted events are notification events that are raised when the update has finished successfully. These events are useful when you want to take further action based on a successful update.

System_CAPS_ICON_note.jpg Note

The Dataset Designer creates a partial class in which validation logic can be added to a dataset. The designer-generated dataset doesn't delete or change any code in the partial class.

You can validate data when the value in a data column changes by responding to the ColumnChanging event. When raised, this event passes an event argument (ProposedValue) that contains the value that's being proposed for the current column. Based on the contents of e.ProposedValue, you can:

  • Accept the proposed value by doing nothing.

  • Reject the proposed value by setting the column error (SetColumnError) from within the column-changing event handler.

  • Optionally use an ErrorProvider control to display an error message to the user. For more information, see ErrorProvider Component.

Validation can also be performed during the RowChanging event. For more information, see How to: Validate Data During Row Changes.

You can write code to verify that each column you want to validate contains data that meets the requirements of your application. Do this by setting the column to indicate that it contains an error if a proposed value is unacceptable. The following examples set a column error when the Quantity column is 0 or less. The row-changing event handlers should resemble the following examples.

To validate data when a row changes (Visual Basic)

  1. Open your dataset in the Dataset Designer. For more information, see How to: Open a Dataset in the Dataset Designer.

  2. Double-click the title bar of the table you want to validate. This action automatically creates the RowChanging event handler of the DataTable in the dataset's partial-class file.

    System_CAPS_ICON_tip.jpg Tip

    Double-click to the left of the table name to create the row-changing event handler. If you double-click the table name, you can edit it.

            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
    

To validate data when a row changes (C#)

  1. Open your dataset in the Dataset Designer. For more information, see How to: Open a Dataset in the Dataset Designer.

  2. Double-click the title bar of the table you want to validate. This action creates a partial-class file for the DataTable.

    System_CAPS_ICON_note.jpg Note

    The Dataset Designer does not automatically create an event handler for the RowChanging event. You have to create a method to handle the RowChanging event, and run code to hook up the event in the table's initialization method.

  3. Copy the following code into the partial class:

    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", "");  
        }  
    }  
    
    

Each row in a data table has a RowState property that keeps track of the current state of that row by using the values in the DataRowState enumeration. You can return changed rows from a dataset or data table by calling the GetChanges method of a DataSet or DataTable. You can verify that changes exist prior to calling GetChanges by calling the HasChanges method of a dataset. For more information about HasChanges, see How to: Check for Changed Rows.

System_CAPS_ICON_note.jpg Note

After you commit changes to a dataset or data table (by calling the AcceptChanges method), the GetChanges method returns no data. If your application needs to process changed rows, you must process the changes before calling the AcceptChanges method.

Calling the GetChanges method of a dataset or data table returns a new dataset or data table that contains only records that have been changed. If you want to get specific records — for example, only new records or only modified records — you can pass a value from the DataRowState enumeration as a parameter to the GetChanges method.

Use the DataRowVersion enumeration to access the different versions of a row (for example, the original values that were in a row prior to processing it).

To get all changed records from a dataset

  • Call the GetChanges method of a dataset.

    The following example creates a new dataset called changedRecords and populates it with all the changed records from another dataset called dataSet1.

                DataSet changedRecords = dataSet1.GetChanges();
    

To get all changed records from a data table

  • Call the GetChanges method of a DataTable.

    The following example creates a new data table called changedRecordsTable and populates it with all the changed records from another data table called dataTable1.

                DataTable changedRecordsTable = dataTable1.GetChanges();
    

To get all records that have a specific row state

  • Call the GetChanges method of a dataset or data table and pass a DataRowState enumeration value as an argument.

    The following example shows how to create a new dataset called addedRecords and populate it only with records that have been added to the dataSet1 dataset.

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

  • The following example shows how to return all records that were recently added to the Customers table:

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

When changes are made to data rows, the dataset retains both the original (Original) and new (Current) versions of the row. For example, before calling the AcceptChanges method, your application can access the different versions of a record (as defined in the DataRowVersion enumeration) and process the changes accordingly.

System_CAPS_ICON_note.jpg Note

Different versions of a row exist only after it has been edited and before it the AcceptChanges method has been called. After the AcceptChanges method has been called, the current and original versions are the same.

Passing the DataRowVersion value along with the column index (or column name as a string) returns the value from that column's particular row version. The changed column is identified during the ColumnChanging and ColumnChanged events. This is a good time to inspect the different row versions for validation purposes. However, if you have temporarily suspended constraints, those events won't be raised, and you will need to programmatically identify which columns have changed. You can do this by iterating through the Columns collection and comparing the different DataRowVersion values.

To get the original version of a record

  • Access the value of a column by passing in the DataRowVersion of the row you want to return.

    The following example shows how to use a DataRowVersion value to get the original value of a CompanyName field in a DataRow:

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

To get the current version of a record

  • Access the value of a column, and then add a parameter to the index that indicates which version of a row you want to return.

    The following example shows how to use a DataRowVersion value to get the current value of a CompanyName field in a DataRow:

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

Creating and Editing Typed Datasets
How to: Connect to Data in a Database
How to: Validate Data in the Windows Forms DataGridView Control
How to: Display Error Icons for Form Validation with the Windows Forms ErrorProvider Component

Show: