Title: THE SECRET LIFE OF TCLIENTDATASET
Question: When asked about my favourite dataaccess component, I always answer: TClientDataset. And this is not only for its well-known features: its being simple to use, but reliable foundation stone to build multitiered applications. There is also some kind of magic in the local applicability of this component: you can always discover something new about it. It is a great field for experimenting, if you enjoy playing rather than using the most obvious ways. It can be an inspiration while remaining still easy, developer-friendly and reliable. This is a true miracle, ins''t it?
Answer:
LOOKUPING
To start, I would like to remind you of one function we already know the Clientdataset can carry out: to be a dataset for lookup fields in another dataset. Receiving its Data from the provider only the first time when a lookup value is needed, the Clientdataset keeps all the information, so that there is no need to call the server for these values again in this session. Of course, you can use an usual Dataset and cached updates for this purpose, but it is well worth doing some simple preliminary tests. Compare the time results and you will be astonished by the difference.
Moreover, there could be a situation in which the usual Dataset will be truly powerless: what if you don't need the lookup data in the database at all! There are plenty of examples of data which is never, or hardly ever, changed. In this case, the standard way to save and economize transactions and database space is to include this information in something like the good old inifiles on the client machine (NAME=VALUE) and to develop some tools to read and translate these values before the data presentation. Using Tclientdataset instead is much more logical and consistent: your datasources will be clearly indicated on your datamodule and the approach to all data can be the same no matter where the data is situated. The Clientdataset decodes and encodes the files by itself and transmitts the data just as if the source was a real table.Moreover, you can easily add a tool which will change this data automatically on all the client machines - using that the clientdataset supports the briefcase model, rarely transacting with the server and applying updates or just replacing the files. It's up to you to choose the concrete approach, but they all are simple, logical and safe.
------
procedure TfrmTypes.FormClose(Sender: TObject; var Action: TcloseAction);
begin
If DataMod.cdsActions.State in [dsEdit, dsInsert] then
DataMod.cdsActions.Post;
If DataMod.cdsPayments.State in [dsEdit, dsInsert] then
DataMod.cdsPayments.Post;
DataMod.cdsActions.MergeChangeLog;
DataMod.cdsPayments.MergeChangeLog ;
DataMod.cdsActions.SaveToFile (ExtractFilePath(Application.Exename)+'Actions.cds);
DataMod.cdsPayments.SaveToFile (ExtractFilePath(Application.Exename)+'Payments.cds);
Listing 1: In this example, two Tclientdatasets are used to give values for lookupfields.The values can be different for different clients and can be, altough rarely, changed by the user. If this occurs, Clientdatasets will save the changes in local files.
------
BACKUPING
Yet another advantage: for what else can we use the wonderful 'bisexuality' of the Clientdataset to respond equally to tables and files? The answer is obvious: for everything previously done by the ASCII files. It is not that I don't rely on the BDE ASCII driver, but how often have you received messages as 'Data structure corruption!, etc., even if you have used it after diligent preparation. There are other market products which do this task efficiently, but our hero beats them all: it is enough to connect a provider and a clientdataset together to transfer all the information from a table to a file. And, if necessary you can also easily send it back to a table, again and again, and there will be no mistakes because of a missed comma or a misscount of a string. In this contest, the ClientDataset may loose in speed, especially for very big tables, but not in safety. It is simple to organise a backup utility this way, to save, to
compress, to transport and to migrate the data. And all you need you already have on your component palette.
----------
unit UnBackup;
interface
----------
implementation
procedure TfrmBackup.FormShow(Sender: Tobject);
begin
Provider.DataSet :=tbEventlogBackup;
cdsBackup.Data:=Provider.Data;
cdsBackup.SaveToFile ('C:\BossHelperBackup);
Application.ProcessMessages;
Timer1.Enabled:=true;
End;
Listing 2: In this example, a Clientdataset and a provider are used to save a file copy of the most important for the application Oracle table on the user machine every time when the user is exiting the application.
--------------
DATEPICKING
The next step in our investigation is: the Clientdataset can produce data for your application. Sounds strange? Look at the following examples.
A client of mine asked to add additional 'Day of week' field to the database application. He told me that when filling data for the previous few days (something often done in his organization) it is much easier to orientate oneself by the days, not by the data and wanted to enter days, not dates on the screen up to seven days back. This task can be performed in Delphi in many different ways, but using a Clientdataset is one the most economical ways. There is one more miracle here: the clientdataset can use a database table or a flat file to work, but in fact it does not need them- it can be a live, selfsupporting dataset even without any external data carrier.
All you need are persistent fields, a dataset creating (right clicking on the component in design time) and an idea how this can be useful to you. I don't know if the result is a 'real' dataset or a brilliant imitation, but it works. I have created dataset with two persistent fields. Every time when the user starts the application, they fill: the first with the date, and the second with the name of the corresponding day of week, starting from the present day and going up to seven days back. So no days repetition will occur in the dataset and you can use it for a lookup field just the same way you would use a 'regular' database-based dataset. When you are choosing a day of the week on the grid, the appropriate date is written in the database and this cannot be done for more than a week back .
-----
procedure TDataMod.DataModuleCreate(Sender: Tobject);
.......
.......
try
cdsweek.Open ;
for iWeek:= 0 to 6 do
begin
cdsweek.Insert;
cdsweekdatenow.AsDateTime := date-iWeek;
cdsweekdayofweek.AsString := FormatDateTime('dddd' ,Date-iWeek);
end;
cdsweek.post;
except
end;
Listing 3:TclientDataset works even without a table or a flatfile and still produces a lookup field. Notice the use of the same 'Insert' and 'Post' as if a real table were connected to the Dataset.
----------------
You dispose of TdateTimePicker to enter a date in your database. But what to do if your client is a web one, created by using the Internet Express technology. I haven't come across an equivalent of the datetimepicker for internet Express yet. You can, of course, write one (send it to me, I will be hapy to have it) or you can use instead...
Yes, you've guessed correctly: a local use of our beloved Tclientdataset. You will have the start (From) and the end (Until) date parameter list for your query by just putting them both on the Web module and filling them on OnCreateWebModule procedure.The process is exactly the same as described above, the only difference is that you may prefer filling up all the dates for a year, or all the months, or whatever works for you. And even one date field in your clientdatasets is enough. Enter the two parameters for the datefield in your XMLBroker; connect them with TquerySelectOptions, compile the project, don't forget to write a query with these parameters in your remote datamodule and enjoy the results: you do have operating datepicking, maybe not as 'pretty' as the Windows one but fully functional on your Web browser! Thanks again to the amazing clientdataset.
And maybe you are already eager to continue this journey...