Handling Cached Update Errors

From RAD Studio
Jump to: navigation, search

Go Up to Using the BDE to cache updates Index

Attention: The Borland Database Engine (BDE) has been deprecated, so it will not be enhanced. For instance, BDE will never have Unicode support. You should not undertake new development with BDE. Consider migrating your existing database applications from BDE to dbExpress.

The Borland Database Engine (BDE) specifically checks for user update conflicts and other conditions when attempting to apply updates, and reports any errors. The dataset component's Bde.DBTables.TBDEDataSet.OnUpdateError event enables you to catch and respond to errors. You should create a handler for this event if you use cached updates. If you do not, and an error occurs, the entire update operation fails.

Here is the skeleton code for an OnUpdateError event handler:

procedure TForm1.DataSetUpdateError(DataSet: TDataSet; E: EDatabaseError;
  UpdateKind: TUpdateKind; var UpdateAction: TUpdateAction);
begin
  { ... perform update error handling here ... }
end;
void __fastcall TForm1::DataSetUpdateError(TDataSet *DataSet,
  EDatabaseError *E, TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
  // Respond to errors here...
}

DataSet references the dataset to which updates are applied. You can use this dataset to access new and old values during error handling. The original values for fields in each record are stored in a read-only TField property called OldValue. Changed values are stored in the analogous TField property NewValue. These values provide the only way to inspect and change update values in the event handler.

Warning: Do not call any dataset methods that change the current record (such as Next and Prior). Doing so causes the event handler to enter an endless loop.

The E parameter is usually of type EDBEngineError. From this exception type, you can extract an error message that you can display to users in your error handler. For example, the following code could be used to display the error message in the caption of a dialog box:

ErrorLabel.Caption := E.Message;
ErrorLabel->Caption = E->Message;

This parameter is also useful for determining the actual cause of the update error. You can extract specific error codes from EDBEngineError, and take appropriate action based on it.

The UpdateKind parameter describes the type of update that generated the error. Unless your error handler takes special actions based on the type of update being carried out, your code probably will not make use of this parameter.

The following table lists possible values for UpdateKind:

UpdateKind values

Value Meaning

ukModify

Editing an existing record caused an error.

ukInsert

Inserting a new record caused an error.

ukDelete

Deleting an existing record caused an error.

UpdateAction tells the BDE how to proceed with the update process when your event handler exits. When your update error handler is first called, the value for this parameter is always set to uaFail. Based on the error condition for the record that caused the error and what you do to correct it, you typically set UpdateAction to a different value before exiting the handler:

  • If your error handler can correct the error condition that caused the handler to be invoked, set UpdateAction to the appropriate action to take on exit. For error conditions you correct, set UpdateAction to uaRetry to apply the update for the record again.
  • When set to uaSkip, the update for the row that caused the error is skipped, and the update for the record remains in the cache after all other updates are completed.
  • Both uaFail and uaAbort cause the entire update operation to end. uaFail raises an exception and displays an error message. uaAbort raises a silent exception (does not display an error message).

The following code shows an OnUpdateError event handler that checks to see if the update error is related to a key violation and, if it is, it sets the UpdateAction parameter to uaSkip:

{ Add 'Bde' to your uses clause for this example }
if (E is EDBEngineError) then
  with EDBEngineError(E) do begin
    if Errors[ErrorCount - 1].ErrorCode = DBIERR_KEYVIOL then
      UpdateAction := uaSkip                      { key violation, just skip this record }
    else
      UpdateAction := uaAbort;               { don't know what's wrong, abort the update }
  end;
// include BDE.hpp in your unit file for this example
void __fastcall TForm1::DataSetUpdateError(TDataSet *DataSet,
  EDatabaseError *E, TUpdateKind UpdateKind, TUpdateAction &UpdateAction)
{
  UpdateAction = uaFail // initialize to fail the update
  if (E->ClassNameIs("EDBEngineError"))
  {
    EDBEngineError *pDBE = (EDBEngineError *)E;
    if (pDBE->Errors[pDBE->ErrorCount - 1]->ErrorCode == DBIERR_KEYVIOL)
      UpdateAction = uaSkip; // Key violation, just skip this record
  }
}
Note: If an error occurs during the application of cached updates, an exception is raised and an error message displayed. Unless the ApplyUpdates is called from within a try...except construct, an error message to the user displayed from inside your OnUpdateError event handler may cause your application to display the same error message twice. To prevent error message duplication, set UpdateAction to uaAbort to turn off the system-generated error message display.

See Also