Gestion des informations d'état dans les modules de données exposés
Remonter à Création de l'application serveur
L'interface IAppServer, utilisée par les ensembles de données client pour communiquer avec les fournisseurs sur le serveur d'applications, est généralement sans état. Lorsqu’une application est sans état, elle ne "mémorise" pas ce qui s’est produit lors des appels précédents effectués par le client. Cette caractéristique est utile si vous regroupez les connexions aux bases de données dans un module de données transactionnel, car votre serveur d'applications n’a pas besoin de différencier les connexions par rapport à des informations persistantes comme l’enregistrement en cours. De même, cette absence d’information d’état est importante lorsque vous partagez les instances des modules de données distants entre de nombreux clients, comme cela se produit avec l’activation "juste à temps" ou le regroupement des objets. Les modules de données SOAP doivent être sans état.
Dans certaines circonstances, toutefois, vous voudrez maintenir des informations d’état entre les appels au serveur d’applications. Par exemple, lorsque vous demandez des données à l'aide de la lecture incrémentielle, le fournisseur sur le serveur d'applications doit "mémoriser" des informations sur les appels précédents (l'enregistrement en cours).
Avant et après tous les appels à l’interface IAppServer effectués par l’ensemble de données client (AS_ApplyUpdates, AS_Execute, AS_GetParams, AS_GetRecords ou AS_RowRequest), il reçoit un événement dans lequel il peut envoyer ou extraire des informations d’état personnalisées. De même, avant et après la réponse des fournisseurs aux appels générés par les clients, ils reçoivent des événements dans lesquels ils peuvent extraire ou envoyer des informations d’état personnalisées. Avec ce mécanisme, vous pouvez communiquer des informations d’état persistantes entre les applications client et le serveur d’applications, même si le serveur d’applications est sans état.
Par exemple, considérez un ensemble de données qui représente la requête paramétrée suivante :
SELECT * from CUSTOMER WHERE CUST_NO > :MinVal ORDER BY CUST_NO
Pour utiliser la lecture incrémentale dans un serveur d’applications sans état, vous pouvez faire ce qui suit :
Lorsque le fournisseur rassemble un ensemble d’enregistrements dans un paquet de données, il note la valeur de CUST_NO sur le dernier enregistrement du paquet :
TRemoteDataModule1.DataSetProvider1GetData(Sender: TObject; DataSet: TCustomClientDataSet); begin DataSet.Last; { move to the last record } with Sender as TDataSetProvider do Tag := DataSet.FieldValues['CUST_NO']; {save the value of CUST_NO } end;
TRemoteDataModule1::DataSetProvider1GetData(TObject *Sender, TCustomClientDataSet *DataSet) { DataSet->Last(); // move to the last record TComponent *pProvider = dynamic_cast<TComponent *>(Sender); pProvider->Tag = DataSet->FieldValues["CUST_NO"]; }
Le fournisseur envoie cette dernière valeur CUST_NO au client après avoir envoyé le paquet de données :
TRemoteDataModule1.DataSetProvider1AfterGetRecords(Sender: TObject; var OwnerData: OleVariant); begin with Sender as TDataSetProvider do OwnerData := Tag; {send the last value of CUST_NO } end;
TRemoteDataModule1::DataSetProvider1AfterGetRecords(TObject *Sender, OleVariant &OwnerData) { TComponent *pProvider = dynamic_cast<TComponent *>(Sender); OwnerData = pProvider->Tag; }
Sur le client, l’ensemble de données client enregistre cette dernière valeur de CUST_NO :
TDataModule1.ClientDataSet1AfterGetRecords(Sender: TObject; var OwnerData: OleVariant); begin with Sender as TClientDataSet do Tag := OwnerData; {save the last value of CUST_NO } end;
TDataModule1::ClientDataSet1AfterGetRecords(TObject *Sender, OleVariant &OwnerData) { TComponent *pDS = dynamic_cast<TComponent *>(Sender); pDS->Tag = OwnerData; }
Avant de lire un paquet de données, le client envoie la dernière valeur de CUST_NO qu’il a reçue :
TDataModule1.ClientDataSet1BeforeGetRecords(Sender: TObject; var OwnerData: OleVariant); begin with Sender as TClientDataSet do begin if not Active then Exit; OwnerData := Tag; { Send last value of CUST_NO to application server } end; end;
TDataModule1::ClientDataSet1BeforeGetRecords(TObject *Sender, OleVariant &OwnerData) { TClientDataSet *pDS = dynamic_cast<TClientDataSet *>(Sender); if (!pDS->Active) return; OwnerData = pDS->Tag; }
Enfin, sur le serveur, le fournisseur utilise la dernière valeur de CUST_NO envoyée comme valeur minimale dans la requête :
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; { force the query to reexecute } 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(); // force the query to reexecute } }
Voir aussi
- Gestion des transactions dans les applications multiniveaux
- Extension de l'interface du serveur d'applications
- Gestion des relations maître/détail
- Configuration du module de données
- Ecriture des applications client Web
- Communication avec l'ensemble de données client
- Utilisation de plusieurs modules de données serveur