The FillError event is most commonly raised when the data being added violates a constraint in the DataSet or when the data being added can't be converted to a .NET Framework data type without a loss of precision. When a FillError event occurs, the current row isn't added to the DataTable. Handling the FillError event allows the error to be resolved and the row to be either added or ignored before resuming the Fill( ) operation with the next row.
The FillError event handler receives an argument of FillErrorEventArgs, which contains specific data about the event that can effectively respond to and handle the error. The Continue property of the FillErrorEventArgs argument determines whether an exception is thrown or processing continues because of the error.
The following example demonstrates handling the FillError event when filling a table containing three columns:
SqlDataAdapter da; // ... code to set up the data adapter da.FillError += new FillErrorEventHandler(da_FillError); DataSet ds = new DataSet(); da.Fill(ds, "MyTable"); private void da_FillError(object sender, FillErrorEventArgs e) { // ... code to identify and correct the error // add the fixed row to the table DataRow dr = e.DataTable.Rows.Add(new object[] {e.Values[0], e.Values[1], e.Values[2]}); // continue the Fill with the rows remaining in the data source e.Continue = true; }
The RowUpdating event is raised before changes to a row are submitted to the data source. The RowUpdating event handler can modify update behavior, providing additional handling or canceling the update for the row. The RowUpdated event is raised after the update command is executed against the data source and is used to respond to exceptions that occur during the update.
The RowUpdating and RowUpdated event handlers receive arguments of SqlRowUpdatingEventArgs and SqlRowUpdatedEventArgs, respectively, containing data specific to each event. The arguments contain among other properties, a reference to the Command object that performs the update, a DataRow object containing the updated data, a StatementType property containing the type of update being performed, an Errors property containing any errors generated, and a Status property. The Status property returns a value of ErrorsOccurred if an error occurred while updating the row. The Status property can control the action to be taken with the current and remaining rows to be updated after an error; an error can be thrown, the current row can be skipped, or all remaining rows can be skipped by setting the Status property after an error.
The following code demonstrates handling the RowUpdating and RowUpdated events:
SqlDataAdapter da; // ... code to set up the data adapter // add the event handlers da.RowUpdating += new SqlRowUpdatingEventHandler(da_RowUpdating); da.RowUpdated += new SqlRowUpdatedEventHandler(da_RowUpdated); DataSet ds = new DataSet(); // ... code to fill the DataSet // ... code to modify the data in the DataSet da.Update(ds, "Orders"); private void da_RowUpdating(object sender, SqlRowUpdatingEventArgs e) { // Write the date, OrderID, and type of update to a log System.IO.TextWriter tw = System.IO.File.AppendText("update.log"); tw.WriteLine("{0}: Order {1} {2}.", DateTime.Now, e.Row["OrderID", DataRowVersion.Original], e.StatementType.ToString()); tw.Close(); } private void da_RowUpdated(object sender, SqlRowUpdatedEventArgs e) { if(e.Status == UpdateStatus.ErrorsOccurred) { // set the error information for the row e.Row.RowError = e.Errors.Message; // skip peocessing the current row and continue with the rest e.Status = UpdateStatus.SkipCurrentRow; } }
An alternative to processing each error in response to the RowUpdated event as shown in this example is to set the DataAdapter ContinueUpdateOnError property to true, allowing all errors to be handled once the update of all rows is complete.