Почему событие TADOQuery AfterOpen не возникает при изменении основной записи?

#delphi #ado #delphi-xe3

#delphi #ado #delphi-xe3

Вопрос:

Рассмотрим, что у нас есть стандартная взаимосвязь master-detail с двумя TADOQuery . При навигации по основному набору данных AfterOpen событие не возникает для подробного набора данных.

Это событие возникает в других пакетах доступа к данным, таких как BDE. Почему это поведение отличается для dbGo?

Часть .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
  

Ответ №1:

Причина поведения компонентов ADO Delphi заключается в том, что при прокрутке основного набора данных выполняется этот код в ADODB.Pas

   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;
  

и ни SetDetailFilter ни RefreshParams не включает закрытие и повторное открытие
подробный набор данных. Requery в конечном итоге вызывает

   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;
  

которое использует определенную возможность (также названную Requery ) объекта набора записей ADO
в основе TCustomADODataSet лежит извлечение соответствующих подробных записей, что значительно эффективнее
чем закрытие и повторное открытие подробного набора данных, вот почему его AfterOpen событие не вызывается.

Смотрите также TDetailDatalink и TMasterDatalink , определенные в DB.Pas.

Комментарии:

1. Спасибо! Отличное объяснение!

Ответ №2:

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

Большинство других пакетов доступа к данным не вызывают события open в этой ситуации. Например, в справке для компонентов FireDAC упоминается использование OnMasterSetValues (которое недоступно с компонентами dbGo):

Используйте обработчик события OnMasterSetValues, чтобы переопределить значения параметров, предоставленные в набор данных сведений из основного набора данных. Кроме того, поскольку события BeforeOpen и AfterOpen не запускаются для подробного набора данных, вместо этого можно использовать OnMasterSetValues .

Таким образом, события open не должны запускаться, но некоторые компоненты доступа к данным предоставляют другие события в этой ситуации.

ссылка: FireDAC.Comp.DataSet.TFDDataSet.OnMasterSetValues

Комментарии:

1. ? Но вопрос не в fDAC.

2. @MartynA Это указывает на то, что рассматриваемые события запускаются не более чем для dbGo и что некоторые компоненты предлагают альтернативное событие при изменении основной записи.

3. Но вопрос OP был почему . Кстати, не мое общее голосование.

4. @MartynA вопрос включает в себя «Это событие возникает в других пакетах доступа к данным, таких как BDE. Почему это поведение отличается для dbGo?» Мой ответ показывает, что первая часть неверна, что делает недействительной часть вопроса.

5. Спасибо! Я Раньше работал с BDE и одной внешней библиотекой, поэтому подумал, что это поведение по умолчанию.