Watch, Follow, &
Connect with Us
Public Report
Report From: Delphi-BCB/Midas/TDataSetProvider    [ Add a report in this area ]  
Report #:  8606   Status: Closed
DSP.AfterApplyUpdates event should *always* be fired.
Project:  Delphi Build #:  7.0.8.1
Version:    7.0 Submitted By:   Dave Rowntree
Report Type:  Minor failure / Design problem Date Reported:  7/9/2004 6:54:34 AM
Severity:    Commonly encountered problem Last Updated: 3/20/2012 2:24:39 AM
Platform:    All versions Internal Tracking #:   204458
Resolution: Fixed (Resolution Comments) Resolved in Build: : 7.0.8.1
Duplicate of:  None
Voting and Rating
Overall Rating: No Ratings Yet
0.00 out of 5
Total Votes: None
Description
Currently, if an unhandled exception is raised in DSP.ApplyUpdates, the DSP.AfterApplyUpdates event is not called.

This prevents the use of DSP.AfterApplyUpdates to de-allocate resources (probably obtained in the DSP.BeforeApplyUpdates event) since it is not guaranteed to be called.

Please make the DSP.AfterApplyUpdates event always fire.

Please make the currently active exception available in the AfterApplyUpdates event, so appropriate action can be taken by app code in the event.
Steps to Reproduce:
None
Workarounds
PROVIDER.PAS
Dave Rowntree 09 July 2004
QC#8606 and QC#8607 amendments.

TCustomProvider = class(TComponent)
  private
    FExported: Boolean;
    FOnDataRequest: TDataRequestEvent;
    FBeforeApplyUpdates: TRemoteEvent;
    FAfterApplyUpdates: TRemoteEvent;
    FBeforeGetRecords: TRemoteEvent;
    FAfterGetRecords: TRemoteEvent;
    FBeforeRowRequest: TRemoteEvent;
    FAfterRowRequest: TRemoteEvent;
    FBeforeExecute: TRemoteEvent;
    FAfterExecute: TRemoteEvent;
    FBeforeGetParams: TRemoteEvent;
    FAfterGetParams: TRemoteEvent;
    FActiveUpdateAbortException: Exception; (**)(* QC#8606 - add this line *)
    FOwnerData: OleVariant; (**)(* QC#8607 - add this line *)
    function GetData: OleVariant;
  protected

    function InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
      out ErrorCount: Integer): OleVariant; virtual; abstract;
    function InternalGetRecords(Count: Integer; out RecsOut: Integer;
      Options: TGetRecordOptions; const CommandText: WideString;
      var Params: OleVariant): OleVariant; virtual;
    function InternalRowRequest(const Row: OleVariant; RequestType: TFetchOptions): OleVariant; virtual;
    procedure InternalExecute(const CommandText: WideString; var Params: OleVariant); virtual;
    function InternalGetParams(Types: TParamTypes = AllParamTypes): OleVariant; virtual;

    procedure SetActiveUpdateException(E: Exception); (**)(* QC#8606 - add this line *)
    property ActiveUpdateException: Exception read FActiveUpdateAbortException; (**)(* QC#8606 - add this line *)
    property OwnerData: OleVariant read FOwnerData write FOwnerData; (**)(* QC#8607 - add this line *)
........



  TDataSetProvider = class(TBaseProvider)
  private
........
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property ActiveUpdateException; (**)(* QC#8606 - add this line *)
    property OwnerData; (**)(* QC#8607 - add this line *)
  published
........

(**)(* QC#8606 and QC#8607 - replacement function *)
(* Since FActiveUpdateException is only required by the AfterApplyUpdates event,
   it would be better as a local variable in TCustomProvider.ApplyUpdates
   if/when this is rolled into the live VCL. It could passed as a parameter
   through the DoAfterApplyUpdates handler, into the AfterApplyUpdates event.*)
function TCustomProvider.ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant;
begin
  SetActiveUpdateException(nil);
  try
    try
      DoBeforeApplyUpdates(OwnerData);
      Self.OwnerData := OwnerData;
      try
        Result := InternalApplyUpdates(Delta, MaxErrors, ErrorCount);
      finally
        OwnerData := Self.OwnerData;
        Self.OwnerData := unassigned;
      end;
    except
      SetActiveUpdateException(AcquireExceptionObject);
      raise;
    end;
  finally
    try
      DoAfterApplyUpdates(OwnerData);
    finally
      SetActiveUpdateException(nil);
    end;
  end;
end;

(**)(* QC#8616 and QC#8617 - rem out this original function *)
{function TCustomProvider.ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant;
begin
  DoBeforeApplyUpdates(OwnerData);
  Result := InternalApplyUpdates(Delta, MaxErrors, ErrorCount);
  DoAfterApplyUpdates(OwnerData);
end;}


........

(**)(* QC#8606 - add this proc *)
procedure TCustomProvider.SetActiveUpdateException(E: Exception);
begin
  FActiveUpdateAbortException := E;
end;

{ TBaseProvider }
........
Attachment
None
Comments

Dave Rowntree at 7/9/2004 7:33:06 AM -
The VCL amendments in the Workaround address this QC report and QC#8607.

Server Response from: ETNACODE01