Monday, April 27, 2009

Supporting state information in remote data modules

The IAppServer interface, which controls all communication between client datasets and providers on the application server, is mostly stateless. When an application is stateless, it does not “remember” anything that happened in previous calls by the client. This stateless quality is useful if you are pooling database connections in a transactional data module, because your application server does not need to distinguish between database connections for persistent information such as record currency. Similarly, this stateless quality is important when you are sharing remote data module instances between many clients, as occurs with just-in-time activation or object pooling.

However, there are times when you want to maintain state information between calls to the application server. For example, when requesting data using incremental fetching,the provider on the application server must “remember” information from previous calls (the current record).
This is not a problem if the remote data module is configured so that each client has its own instance. When each client has its own instance of the remote data module, there are no other clients to change the state of the data module between client calls.

However, it is reasonable to want the benefits of sharing remote data module instances while still managing persistent state information. For example, you may need to use incremental fetching to display a dataset that is too large to fit in memory at one time.
Before and after any calls to the IAppServer interface that the client dataset sends to the application server (AS_
ApplyUpdates, AS_Execute, AS_GetParams, AS_GetRecords, or AS_RowRequest), it receives an event where it can send or retrieve custom state information. Similarly, before and after providers respond to these client-generated calls, they receive events where they can retrieve or send custom state information. Using this mechanism, you can communicate persistent state information between client applications and the application server, even if the application server is stateless. For example, to enable incremental fetching in a stateless application server, you can do the following:

Use the client dataset’s BeforeGetRecords event to send the key value of the last record to the application server:

TDataModule1::ClientDataSet1BeforeGetRecords(TObject *Sender; OleVariant &OwnerData)

{
TClientDataSet *pDS = (TClientDataSet *)Sender;
if (!pDS->Active)
return;
void *CurRecord = pDS->GetBookmark(); // save current record
try
{
// locate the last record in the current packet. Note this only works if FetchOnDemand
// is False. If FetchOnDemand is True, you can save the key value of the last record
// fetch in an AfterGetRecords event handler and use that instead
pDS->Last(); // locate the last record in the new packet

OwnerData = pDS->FieldValues["Key"]; // Send key value for the last record to app server
pDS->GotoBookmark(CurRecord); // return to current record
}
__finally
{
pDS->FreeBookmark(CurRecord);
}
}

On the server, use the provider’s BeforeGetRecords event to locate the appropriate set of records:

TRemoteDataModule1::Provider1BeforeGetRecords(TObject *Sender, OleVariant &OwnerData)

{
TLocateOptions opts;
if (!VarIsEmpty(OwnerData))
{
TDataSet *pDS = ((TDataSetProvider *)Sender)->DataSet;
if (pDS->Locate("Key", OwnerData, opts))
pDS->Next;
}
incremental fetching

No comments:

Post a Comment