Back in year 2000 I faced a problem trying to build my accounting platform to work in 3 tier client/server mode. In classic desktop applications I had separated database access logic and business rules from the user interface forms by using Delphi’s TDatamodule. A small but essential piece of this separation was lookup fields that once defined in the datamodule’s datasets should work transparently on UI forms with no further configuration.
But in the 3-tier model this could not be done, because TClientDataset in the client application receives the datapacket with lookup fields as data (fkData) and readonly. That seems logical as lookupfield info (LookupDataset property mainly) is unknown to the client. So the solution was to add clientdatasets for each server lookupdataset at the client and construct new lookup fields in the dataset that needed such referencies.
Problem! The level of abstraction of data I wanted for UI forms was broken, and even putting them in a client TDatamodule would be a break to the abstraction of data for the framework.
But in the 3-tier model this could not be done, because TClientDataset in the client application receives the datapacket with lookup fields as data (fkData) and readonly. That seems logical as lookupfield info (LookupDataset property mainly) is unknown to the client. So the solution was to add clientdatasets for each server lookupdataset at the client and construct new lookup fields in the dataset that needed such referencies.
Problem! The level of abstraction of data I wanted for UI forms was broken, and even putting them in a client TDatamodule would be a break to the abstraction of data for the framework.
Did I mention “…could not be done”?
Shame of me, I am a Delphi developer.
I spend some time reading the sources to figure out exactly what TDatasetProvider is doing behind the scenes and concluded that it would be possible to overcome the default behavior. The idea was to gather info about lookup fields, send them to the client where they can be processed and simulate lookup functionality. The process should be transparent to the client so I decided to embed it in a derived TClientDataset. On server side a procedure called from provider’s OnGetDatasetProperties should do the job of collecting and packaging needed info.
The result was “LookCDS”, a small library set of functions, classes and components for Delphi that enables and utilizes at client side the lookup fields defined in a Datasnap remote module. TlkClientDataset, a TClientDataset descendant, contained in LookCDS lib is the main component that supports transparent utilization of server side lookup fields. The library consists of two source files.
- DB_LooksClient.pas: It mainly contains TlkClientDataset, a derived TClientDataset to use at client side.
- UtilLookCDS.pas: Functions and definitions used by DB_LooksClient at client side and by TDatasetProvider at server side.
On server side
- Define lookup fields as usual and just set their provider flags pfInUpdate & pfInWhere to false.
- Add TDatasetProvider component for any lookup dataset your fields refer to and you want to be enabled in the client.
- At the provider of the main dataset (that with lookupfields) add a call to “ProvideDatasetProperties” (in UtilLookCDS.pas) utility procedure.
- Use TlkClientDataset instead of the usual TClientDataset
That's all.
You can download the “LookCDS” files and a simple Datasnap XE2 demo here: http://users.hol.gr/~georgev/delphi.htm
and at sourceforge project: http://sourceforge.net/projects/lookcds/
Very informative and impressive post you have written, this is quite interesting and i have went through it completely, an upgraded information is shared, keep sharing such valuable information. Desentupimento em SP
ReplyDelete