Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't TADOQuery AfterOpen event occur when master record is changed?

Consider we have a standard master-detail relationship with two TADOQuery. When navigation over master dataset takes place, an AfterOpen event doesn't rise for the detail dataset.

This event is rised in other data access packages, such as BDE. Why does this behavior differ for dbGo?

A part of .dfm:

  object DataSource1: TDataSource
    DataSet = SDQuery1
    Left = 504
    Top = 72
  end
  object DataSource2: TDataSource
    DataSet = SDQuery2
    Left = 520
    Top = 360
  end
  object ADOConnection1: TADOConnection
    LoginPrompt = False
    Left = 336
    Top = 464
  end
  object ADOQuery1: TADOQuery
    Connection = ADOConnection1
    Parameters = <>
    Left = 504
    Top = 160
  end
  object ADOQuery2: TADOQuery
    Connection = ADOConnection1
    AfterOpen = ADOQuery2AfterOpen // <- rised when dataset was opened at first time only
    DataSource = DataSource1
    Parameters = <>
    Left = 520
    Top = 296
  end
like image 615
Miamy Avatar asked Jan 01 '23 03:01

Miamy


2 Answers

The reason for the behaviour of the Delphi ADO components is that when the Master dataset scrolls, this code in ADODB.Pas executes

  procedure TCustomADODataSet.MasterChanged(Sender: TObject);
  begin
    if not Active then Exit;
    if Parameters.Count = 0 then
    begin
      CheckBrowseMode;
      if SetDetailFilter then First;
    end else
      RefreshParams;
  end;

and neither SetDetailFilter nor RefreshParams involves closing and re-opening the Detail dataset. Requery eventually calls

  procedure TCustomADODataSet.InternalRequery(Options: TExecuteOptions = []);
  begin
    if FConnectionChanged then
      DatabaseError(SCantRequery);
    try
      Recordset.Requery(ExecuteOptionsToOrd(Options));
    except
      if Recordset.State = adStateClosed then Close;
      raise;
    end;
    DestroyLookupCursor;
  end;

which uses a specific capability (also named Requery) of the ADO RecordSet object underlying the TCustomADODataSet to retrieve the matching detail records which is significantly more efficient than closing and re-opening the Detail dataset, which is why its AfterOpen event is not called.

See also TDetailDatalink and TMasterDatalink defined in DB.Pas.

like image 195
MartynA Avatar answered Jan 15 '23 14:01

MartynA


This event is raised in other data access packages, such as BDE. Why does 
this behavior differ for dbGo?

Most other data access packages do not raise the open events in this situation. For example the help for the FireDAC components mentions using OnMasterSetValues (which is not available with the dbGo components):

Use the OnMasterSetValues event handler to override parameter values supplied to the detail dataset from the master dataset. Also, as the BeforeOpen and AfterOpen events do not fire for a detail dataset, OnMasterSetValues can be used instead.

So the open events aren't supposed to fire but some data access components provide other events in this situation.

ref: FireDAC.Comp.DataSet.TFDDataSet.OnMasterSetValues

like image 28
Brian Avatar answered Jan 15 '23 14:01

Brian