Gestion des informations d'état dans les modules de données exposés

De RAD Studio
Aller à : navigation, rechercher

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