Statusinformationen in Datenmodulen unterstützen

Aus RAD Studio
Wechseln zu: Navigation, Suche

Nach oben zu Serveranwendung erstellen


Das Interface IAppServer, das Client-Datenmengen für die Kommunikation mit Providern auf dem Anwendungsserver verwenden, ist fast immer statuslos. Eine statuslose Anwendung "erinnert" sich nicht an die Vorgänge in den vorhergehenden Client-Aufrufen. Diese Statuslosigkeit ist bei der Objektverwaltung von Datenbankverbindungen in einem transaktionalen Datenmodul erwünscht, da der Anwendungsserver nicht zwischen Datenbankverbindungen aufgrund von persistenten Informationen (wie dem aktuellen Datensatz) unterscheiden muss. Entsprechendes gilt, wenn Instanzen von Remote-Datenmodulen von mehreren Clients genutzt werden, wie das bei der Bedarfsaktivierung und dem Objekt-Pooling der Fall ist. SOAP-Datenmodule müssen statuslos sein.

Es gibt aber Situationen, in denen Statusinformationen aus vorhergehenden Aufrufen des Anwendungsservers benötigt werden. So benötigt der Provider auf dem Anwendungsserver beim inkrementellen Abrufen von Daten Informationen über den vorhergehenden Aufruf (den aktuellen Datensatz).

Vor und nach Aufrufen des IAppServer-Interface, die von der Client-Datenmenge an den Anwendungsserver gesendet werden (AS_ApplyUpdates, AS_Execute, AS_GetParams, AS_GetRecords oder AS_RowRequest), empfängt dieser ein Ereignis, das es ermöglicht, Statusinformationen zu senden oder abzurufen. In ähnlicher Weise empfangen die Provider entsprechende Ereignisse vor und nach der Beantwortung der Client-Anforderungen. Damit ergibt sich die Möglichkeit, persistente Statusinformationen zwischen Client-Anwendungen und einem statuslosen Anwendungsserver auszutauschen.

Betrachten Sie beispielsweise eine Datenmenge, die sich aus der folgenden parameterisierten Abfrage ergibt:

SELECT * from CUSTOMER WHERE CUST_NO > :MinVal ORDER BY CUST_NO

In diesem Fall lässt sich das inkrementelle Abrufen wie folgt für einen statuslosen Anwendungsserver aktivieren.

Wenn die Provider-Komponente eine Gruppe von Datensätzen in einem Datenpaket anordnet, vermerkt sie den Wert des Feldes CUST_NO des letzten Datensatzes im Paket:

TRemoteDataModule1.DataSetProvider1GetData(Sender: TObject; DataSet: TCustomClientDataSet); 
begin 
  DataSet.Last; { letzten Datensatz auswählen } 
  with Sender as TDataSetProvider do 
    Tag := DataSet.FieldValues['CUST_NO']; { Wert von CUST_NO speichern } 
end;
TRemoteDataModule1::DataSetProvider1GetData(TObject *Sender, TCustomClientDataSet *DataSet) 
{ 
  DataSet->Last(); // letzten Datensatz auswählen 
  TComponent *pProvider = dynamic_cast<TComponent *>(Sender); 
  pProvider->Tag = DataSet->FieldValues["CUST_NO"]; 
}

Die Provider-Komponente sendet diesen letzten Wert von CUST_NO nach der Übermittlung des Datenpakets an den Client:

TRemoteDataModule1.DataSetProvider1AfterGetRecords(Sender: TObject; 
                   var OwnerData: OleVariant);
begin 
  with Sender as TDataSetProvider do 
    OwnerData := Tag; { letzten Wert von CUST_NO senden } 
end;
TRemoteDataModule1::DataSetProvider1AfterGetRecords(TObject *Sender, OleVariant &OwnerData)
{ 
  TComponent *pProvider = dynamic_cast<TComponent *>(Sender); 
  OwnerData = pProvider->Tag; 
}

Der Client speichert diesen Wert von CUST_NO in der Client-Datenmenge:

TDataModule1.ClientDataSet1AfterGetRecords(Sender: TObject; var OwnerData: OleVariant); 
begin 
  with Sender as TClientDataSet do 
    Tag := OwnerData; { letzten Wert von CUST_NO speichern } 
end;
TDataModule1::ClientDataSet1AfterGetRecords(TObject *Sender, OleVariant &OwnerData)
{ 
  TComponent *pDS = dynamic_cast<TComponent *>(Sender); 
  pDS->Tag = OwnerData; 
}

Vor dem Abruf eines Datenpakets sendet der Client den ihm übermittelten letzten Wert von CUST_NO:

TDataModule1.ClientDataSet1BeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); 
begin 
  with Sender as TClientDataSet do 
  begin 
    if not Active then Exit; 
    OwnerData := Tag; { letzten Wert von CUST_NO an den Anwendungsserver senden } 
  end; 
end;
TDataModule1::ClientDataSet1BeforeGetRecords(TObject *Sender, OleVariant &OwnerData)
{
  TClientDataSet *pDS = dynamic_cast<TClientDataSet *>(Sender);
  if (!pDS->Active) 
    return; 
  OwnerData = pDS->Tag; 
}

Auf dem Server setzt die Provider-Komponente den gesendeten Wert von CUST_NO als Minimumwert in der Abfrage ein:

TRemoteDataModule1.DataSetProvider1BeforeGetRecords(Sender: TObject; 
                    var OwnerData: OleVariant);
begin
  if not VarIsEmpty(OwnerData) then 
    with Sender as TDataSetProvider do 
      with DataSet as TSQLDataSet do 
      begin 
        Params.ParamValues['MinVal'] := OwnerData; 
        Refresh; { erneute Ausführung der Abfrage erzwingen } 
      end; 
end;
TRemoteDataModule1::DataSetProvider1BeforeGetRecords(TObject *Sender, OleVariant &OwnerData)
{
  if (!VarIsEmpty(OwnerData)) 
  {
    TDataSetProvider *pProv = dynamic_cast<TDataSetProvider *>(Sender);
    TSQLDataSet *pDS = (dynamic_cast<TSQLDataSet *>(pProv->DataSet);
    pDS->Params->ParamValues["MinVal"] = OwnerData; 
    pDS->Refresh(); // erneute Ausführung der Abfrage erzwingen 
  }
}

Siehe auch