Committing and Discarding Changes

When a DataRow is modified, ADO.NET marks the row as having a changes and sets the RowState of the DataRow to Added, Modified, or Deleted, as appropriate. ADO.NET also maintains version information by storing both Original and Current versions of each row. Together, this information allows ADO.NET or an application to identify the rows and columns that have been changed.

The AcceptChanges( ) and RejectChanges( ) methods either accept or reject the changes that have been made to the DataSet since it was last loaded from the data source or since AcceptChanges( ) was last called.

The AcceptChanges( ) method commits all pending changes within the DataSet. Calling AcceptChanges( ) changes the RowState of Added and Modified rows to Unchanged. Deleted rows are removed. The Original values for the DataRow are set to the Current values. Calling the AcceptChanges( ) method has no effect on the data in the underlying data source.

The AcceptChanges( ) method is implicitly called on a row when the DataAdapter successfully updates that row back to the data source when the Update( ) method is called. As a result, when a DataAdapter is used to update the data source with the changes made to the DataSet, AcceptChanges( ) doesn’t need to be called. Calling AcceptChanges( ) on a DataSet filled using a DataAdapter effectively removes all information about how the DataSet has been changed since it was loaded. This makes it impossible to reconcile those changes back to the data source using the Update( ) method of the DataSet.

The following example demonstrates the AcceptChanges( ) method:

ds.AcceptChanges();

The RejectChanges( ) method cancels any pending changes within the DataSet. Rows marked as Added are removed from the DataSet. Modified and Deleted rows are returned to their Original state. The following example demonstrates the RejectChanges( ) method:

ds.RejectChanges();

The following example illustrates the concepts just explained:

// create a table with one column

DataTable dt = new DataTable();

dt.Columns.Add("MyColumn",  typeof(System.String));



// add three rows to the table

DataRow row;



row = dt.NewRow();

row["MyColumn"] = "Item 1";

dt.Rows.Add(row);



row = dt.NewRow();

row["MyColumn"] = "Item 2";

dt.Rows.Add(row);



row = dt.NewRow();

row["MyColumn"] = "Item 3";

dt.Rows.Add(row);



dt.AcceptChanges();



// modify the rows



dt.Rows[0]["MyColumn"] = "New Item 1"; // DataRowState=Modified

dt.Rows[1].Delete();                   // DataRowState=Deleted

//dt.Rows[2]                           // DataRowState=Unchanged



dt.Rows[0].AcceptChanges();            // DataRowState=Unchanged,

                                       // MyColumn value="New Item 1";

dt.Rows[1].RejectChanges();            // DataRowState=Unchanged,

                                       // row not deleted

The DataTable and DataRow objects also expose an AcceptChanges( ) method and a RejectChanges( ) method. Calling these methods on the DataSet implicitly calls these methods for all DataRow objects in the DataSet.

The HasChanges( ) method of the DataSet indicates whether the DataSet has changes, including Added, Deleted, or Modified rows. The method accepts an optional DataRowState argument that causes the method to returns a value from the DataSetRow enumeration if the DataSet has changes:

// check if there are any changes to the DataSet

Boolean hasChanges = ds.HasChanges();



// check if there are modified rows in the DataSet

Boolean hasModified = ds.HasChanges(DataRowState.Modified);

The GetChanges( ) method creates a copy of the DataSet containing all the changes that have been made since it was last loaded or since AcceptChanges( ) was called. The method takes an optional DataRowState argument that specifies the type of row changes the DataSet should include. The GetChanges( ) method can select the data that has been modified in a DataSet so that only the changed data rather than the entire DataSet is returned. This subset of the DataSet that contains just the changed data can improve performance of disconnected applications by reducing the amount of information that needs to be transmitted between different application domains.

The HasChanges( ) method can be called first to determine whether GetChanges( ) needs to be called. The following example show how to use the HasChanges( ) and GetChanges( ) methods:

// check to see whether GetChanges needs to be called

if (ds.HasChanges())

{

    // create a DataSet containing all changes made to DataSet ds

    DataSet dsChange = ds.GetChanges();



    // create a DataSet containing only modified rows in DataSet ds

    DataSet dsModified = ds.GetChanges(DataRowState.Modified);

}