Monday, January 12, 2015

Now Available: Delphi in Depth: ClientDataSets 2nd Edition

I published the original Delphi in Depth: ClientDataSets book back in March of 2011. At the time I believe it was my 24th book on computer software, though I must admit that I've lost count. Nonetheless, I greatly appreciated the many kind comments I've received from readers since its publication, even though it is a Delphi book "about one component."

I decided to update the code samples following the release of Delphi XE7. My original code samples made use of the Borland Database Engine and the sample Paradox tables that shipped with Delphi, which permitted those code samples to be compiled and run without any additional configuration, something that I felt was important.

Things changed with the release of Delphi XE7. The BDE is no longer installed by default. In addition, Delphi Professional (and higher) now ships with an alternative database solution that can be used without any additional configuration. This solution, which makes use of FireDAC and InterBase, did not exist when the first edition of this book was published.

Once I started updating the code samples to use FireDAC and InterBase, I realized that there were also a few additions that I could make to the original book. For example, the new FieldOptions property introduced to TDataSet in Delphi XE6 gave developers additional flexibility in their use of persistent fields, such as calculated and internal calc fields. A nod to LiveBindings would also be warranted.

It didn't take long before I concluded that it was time to give the book a good once over, tweaking the odd description here and there, adding material where appropriate, and correcting a few missed typos. And, of course, using the new FireDAC/InterBase examples in the book's code listings. I also updated all of the figures in the book to show the latest version of Delphi at the time of my writing (XE7). The original BDE/Paradox examples are still available for download, which is necessary in order to support older versions of Delphi, those prior to XE5. XE5 was the first version of FireDAC to use the new FD prefix in component names, as well as the new FireDAC unit names.

Permit me now to anticipate a question that is sure to come up. "What if I bought the original edition of Delphi in Depth: ClientDataSets? Should I buy the 2nd edition?" Well, you probably don't need to buy the 2nd edition unless you want to have the most current version on your bookshelf. In updating the 2nd edition I re-read, for the purpose of correcting and editing, every page of the original manuscript many times. And, for the most part, I was very happy with what I had written. As a result, there are large segments from the original text that are unchanged, or have inconsequential changes in the wording. Yes, I did add sections on FieldOptions, LiveBindings, and special filter operations. There are also a few additional examples and extended discussions.

I should also note that you can use the new FireDAC/InterBase samples with the original book. Visit the book's download site, listed in Appendix A of the original publication. There you will find the FireDAC/InterBase code sample download, along side the BDE/Paradox code download. Again, these FireDAC examples only work with Delphi XE5 and later, so the BDE-based examples are still available for use with earlier versions of Delphi.

I should also note that I removed three chapters that appeared at the end of the original book from the 2nd edition. Those chapters covered DataSnap, with a mix of COM-based DataSnap and the newer DataSnap introduced in Delphi 2009. While ClientDataSets played a central role in the COM-based DataSnap (the obsolete version), they are one of many options in the new DataSnap. In the end, I concluded that the DataSnap chapters were out of place.

I am releasing two versions of Delphi in Depth: ClientDataSets 2nd Edition. The printed version is available on CreateSpace and Amazon. And, in response to popular request, I am releasing a PDF version on FastSpring. You can find links to these releases from the book's web site at http://www.JensenDataSystems/cdsbook2.

I am very happy with how Delphi in Depth: ClientDataSets 2nd Edition turned out. I hope that you are too.

Publication Date: Jan 07 2015
ISBN/EAN13: 150584018X / 9781505840186
Page Count: 358 pages, 7.44" x 9.69"

Web Site: http://www.JensenDataSystems/cdsbook2

15 comments:

  1. I am curious about the futur of the TClientDataSet in RAD Studio. What I read in the net is, that EMB doesn't improve that component anymore. The are now focused on TFDMemTable. It seams the want to replace TClientDataSet with TFDMemTable. Is that rumor true?

    ReplyDelete
    Replies
    1. Embarcadero has not done much to the ClientDataSet in many years, though to be honest, its feature set is more or less complete. It is true that the FDMemTable will be the focus of new development, but it still has a long way to go before it will be a suitable replacement for the ClientDataSet. In short, the FDMemTable lacks a number of useful features that are supported by ClientDataSets, such as cached updates with nested datasets. I am not knocking FDMemTable, I am just saying that if you replace your ClientDataSets with FDMemTables today you will lose some pretty important functionality.

      Delete
  2. It would be neat if you were to publish the first chapter as a "teaser".

    ReplyDelete
    Replies
    1. Olaf: Great idea. You can now find a link to the book's foreword, written by Marco Cantù, and the introduction, which describes the book and its contents, at the following Web site:
      http://JensenDataSystems.com/cdsbook2

      Delete
  3. I used TClientDataSet.Filiter.
    CDS's Filiter support "Trim" statement in Delphi help doc.

    It support "Trim(Name, '.')". But, How to used the statement?

    ReplyDelete
    Replies
    1. You will find the answer here: http://caryjensen.blogspot.com/2015/02/using-trim-in-clientdataset-filters.html

      Delete
  4. My boss bought this book at my request. I'm looking forward to finally getting to grips with what these components can do, instead of just using them to read data from SQL Server, and building my own SQL statements for insert/updates like some sort of caveman :) Thank you for writing the book! BTW in chapter one, where you explain that CDS can be used for a simple local, single user system, I think a more thorough explanation and sample might help. I dug around the sample projects to find which one was applicable and it didn't take long to understand the moving parts, but as an introductory segment, I'd have liked to be shown how to make a simple "save to file" application, with all the moving parts (Load/Save/Createdataset/filename/datasetprovider/clientdataset) explained, as if to a caveman like me :)

    Thanks again!

    ReplyDelete
    Replies
    1. Brian:

      There are several examples that demonstrate the basics of a simple, local, single user system. These include CDSFilter and CDSSearch. However, the one that really comes closest is the VideoLibrary example. That example can be found in both the Paradox and InterBase versions of the code download.

      There is one point that I want to emphasis. A stand alone system does not use a DataSetProvider. DataSetProviders are used to interface a ClientDataSet with an underlying database server. In a stand alone, single user system the ClientDataSet loads and saves its data from a local file. I hope this helps.

      Delete
  5. About Nested DataSets.
    Could define nested dataset at runtime in opened ClientDataSet?

    My table structs and code below:
    CREATE TABLE myBook(ISBN NVARCHAR(20), BKName NVARCHAR(50), EmpID INTEGER, PRIMARY KEY(ISBN, EmpID));
    GO
    CREATE TABLE myEmp(EmpID INTEGER, EmpName NVARCHAR(10), PRIMARY KEY(EmpID));
    GO

    SQLQuery1.CommandText := 'SELECT * FROM myBook';
    ClientDataSet1.Data := DataSetProvider1.Data;
    SQLQuery2.CommandText := 'SELECT * FROM myEmp';
    ClientDataSet2.Data := DataSetProvider2.Data;

    ClientDataSet1.Close;
    ClientDataSet1.FieldDefs.Clear();
    ClientDataSet1.FieldDefs.Update();
    with ClientDataSet1.FieldDefs.AddFieldDef do
    begin
    Name := 'SubNested';
    DataType := ftDataSet;
    end;
    for vPos := 0 to ClientDataSet1.FieldDefs.Count-1 do
    ClientDataSet1.FieldDefs[vPos].CreateField(ClientDataSet1);
    ClientDataSet1.Open;

    I get a error message: 'Field 'SubNested' not found' in CreateField line, why?

    ReplyDelete
    Replies
    1. The answer is No. You cannot define any part of the ClientDataSets structure, including the nested datasets, once the ClientDataSet is active (has been created). Sorry.

      Delete
  6. Sorry, I fix my table structs below:
    CREATE TABLE myBook(ISBN NVARCHAR(20), BKName NVARCHAR(50), PRIMARY KEY(ISBN));
    GO
    CREATE TABLE myEmp(ISBN NAVRCHAR(20), EmpID INTEGER, EmpName NVARCHAR(10), PRIMARY KEY(ISBN,EmpID));
    GO

    ReplyDelete
  7. Hi Mr. Cary:
    Im new to ClientDatasets. I amreading your articles on:
    http://delphi.about.com/od/usedbvcl/a/tclientdataset.htm
    So my fundamental question is (I have Delphi 7):
    For example, I can use
    AdoQuery <-- DataSetProvider <-- ClientDataset
    | ^
    | |<-- DataSource <-- DBGrid
    |
    ^<-- Another_DataSource <-- Another_DBGrid

    That weird configuration (for the last part (Another_DataSource, Another_DBGrid )), is only to show that seems like the ADoQuery loads data from its query, for its own use.

    So, i was wondering if
    AdoQuery <-- DataSetProvider <-- ClientDataset
    ^
    |<-- DataSource <-- DBGrid
    alone, makes the application that uses a ClientDataSet to load TWO times (one for the query, one for the ClientDataSet) the data, and so use TWO TIMES more memory than a "standard" way like (not counting the memory that a DBGrid uses)
    AdoQuery <-- DataSource <-- DBGrid

    I hope i was clear. Thank you a lot for your time.

    ReplyDelete
  8. In other words (not counting the, DataSource and DBGrid): ¿
    AdoQuery <-- DataSetProvider <-- ClientDataset <-- DataSource <-- DBGrid

    consumes two times more memory than
    AdoQuery <-- DataSource <-- DBGrid

    because AdoQuery gets memory for its data and for definition ClientDataSet is a "in memory data".?

    ReplyDelete
    Replies
    1. alschopenhauer: Not sure I am entirely sure what you are asking, but I think I have a good idea. If the ADOQuery is closed prior to the DataSetProvider opening it, the DataSetProvider will close that ADOQuery once the data is loaded into the ClientDataSet. So, one set of data in memory, not two.

      Delete