Statusinformationen in Datenmodulen unterstützen
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 } }