Saturday, December 24, 2011

1st Impressions on Embarcadero Delphi XE2 - Part 2

Though tomorrow is Christmas Day, i could not hold back and just turned on my workstation to play with my gift. 

Running again Delphi XE2, a notification showed up that Update 3 is available for download. It took a while to complete but i have to notice that all installation steps so far completed very smooth, despite the big amount of programs and features that installed. That is very nice and gives me confidence for the future.

Ok, Delphi XE2 pinned to start menu, let’s start discovering the new development environment.

Checking Installed packages and what is available for download. QuickReports & FastCube are available for download. For the first I will need it in order to convert my previous apps due to the extensive usage I had done, and I even derived some of these to suit my needs.
ADO DB is installed so normally I will not any problem. As for other components I will check on the go.

Looking at Help, “What's New in the Help, and Where is Everything” it says I must take a “Tour of the IDE”. It is comprehensive presentation of the IDE features and finally I found out what the “Structure View” window is (see my 1st post), it is the Object Treeview from past versions of Delphi. Also “History Manager” and the Subversion integration is a very usefull new feature that “lets you see and compare versions of a file, including multiple backup versions, saved local changes, and the buffer of unsaved changes for the active file. If the current file is under version control, all types of revisions are available in the History Manager.

Next stop is at a feature of modern application development tools, that old guys like me can truly appreciate, “Refactoring”. When you have written thousands lines of code in COBOL using just a plain text editor, or even used the first versions of IDE based tools like Delphi at late 90's, you can tell the difference about massive code modifications at the years before Refactoring. As help says “Refactoring is a technique you can use to restructure and modify your existing code in such a way that the intended behavior of your code stays the same. Refactoring allows you to streamline, simplify, and improve both performance and readability of your application code”. I will not get you any deeper to this but defenitely is something that every developer who builds applications with multiple units/forms should take into great consideration.

I will spend the rest of the night looking to demos, reading articles and watching videos at Embarcadero’s Developer Network. My purpose is to feel as much confortable with my new toy so I can start migrating old code libraries and my Data CentricApplication Framework* before I start migrating applications.

*I am preparing some articles for the “Data Centric Application Framework” and hope to publish them soon.

1st Impressions on Embarcadero Delphi XE2

This year i decided to make a Christmas present to myself, a brand new Delphi version.

After working with Delphi 6 for many years and refusing to go further due to Borland’s –whatever- policy at the early millennium, i have decided to take a better look at what Embarcadero has done the last couple of years. A nice surprise hit me, i just was amazed with the brand new Delphi XE2 which seems to be the next revolution of Delphi after the mid and late 90’s.

During the last years I strangled to find something that could replace my good old Delphi 6, and lately tried to take a look at .Net and Visual Studio. But I just could not abandon my beloved IDE and programming framework that I have built during the 15 years of development. Old dogs like me does not do (trust) new tricks. So i stacked here hoping and waiting, having my eyes looking at the latest developments of Embarcadero.

Yesterday during late night hours and after a couple of days that i had attended the David’s 24 hours of Delphi i decided to give a try and downloaded the trial version. By my surprise while i was registering to Embarcadero's developers network i found out that they had transferred my old -and forgotten- Borland’s developer network account, back from 1997, to their new network. And more over it was eligible for an upgrade. The decision was just a flash in my mind and the brand new Delphi XE2 Enterprise is now in my hands.

Due to the very late night time, i decided to try getting some sleep, even though i have serious trouble doing so(!), and install it first thing in the morning. So i did, Morpheus (the Greek ancient god of sleep) came to me a couple of hours after that but that is not so necessary of course...

First thing in the morning, a huge cup of coffee -the first from a series- and power on my workstation. Right after I started the installation procedure.

Huge installation makes me thinking of what I could expect. After half an hour and so far, all running smooth, but my experience with every installation procedure in Windows keeps me nervous for the law of Murphy! Almost one hour after starting the install process and it is still downloading files, right now it is downloading Help system's Web Media.

As i am writing these lines, installation keeps going on, Help system, Final Builder, CodeSite and others. Finally i see the end of the installation. Hit finish and waiting for the application to start... waiting ... waiting ... waiting ... is something wrong? Guess no, it just does not start automatically; i have to run it by my self.
Started, registering, and waiting to load and … my 23” monitor dominated. It is alive!!!



First impression: solid and consistent environment, not what i was used to from the old Delphi's IDE with disconnected windows but i think i can adapt even if it looks a bit like VS... I have two boxes on the left “Structure” which I do not know –yet- what is it and Object Inspector my friend from the past I suspect. At the right side I see Project Management box with Model View and Data Explorer tabs and the Tool Palette box which I was used to see just under the main menu in the old IDE. In the centre and main area there is a Welcome page that has a very nice and clear menu Projects, News, Resources and Documentation, each one having a bunch of sub items to choose. Having a quick look at the IDE menu i found my self been very familiar with most of the choices.
Yes definitely seems like i am at home!!!

Ok, now i have a page opened in my browser that gives me links to download some things, ER/Studio, DB Power Studio, Interbase XE Developer edition and partner products AQTime, IP*Works and Partner Software ISO. So i do started downloading... it is Sat 12:30 and it will take approximately 1:20 hours. I have time to check for the updates.

I see in About box that Update 1 is already installed and i am looking for a “check for updates” item. I know from embarcadero's website that there is an update 2 available.
Cannot locate such a quick option, so i will navigate to various others like the resources menu in welcome page and directly from Embarcadero's website.
Sorry, i forgot to RTFM :) installation instructions that says "Select Start | Programs | Embarcadero RAD Studio XE2 | Check for updates.". It is just another option at the program menu group but it would be nice to have it also embedded somewhere in the IDE. I hit it and, Yes! it shows Update 3 is available! I will wait for other downloads to finish and come back to it.

Nice option at my EDN account "My registered user downloads" where are a bunch of downloads available. I am afraid i will become a download junkie (!), so i will stop here and come back later when i have completed the setup of everything i need.
Have a merry Christmas day all you out there.

Tuesday, December 13, 2011

A journey to Delphi TParams - 1

Among other amazing things around Delphi is a litle object called “TParam” which is derived from TCollectionItem and it's associated collection object “TParams”.

Both are declared in DB.pas unit and their short description in delphi help says:
TParam: "TParam represents a field parameter for a query or stored procedure."
TParams: "TParams manages a list of field parameters."

That's all, the name as per this help specifies it's usage. So what is the amazing about TParam and TParams?
Or it is not that's all...?

Let's forget the association of the name with the usage and the usage itself and do some brainstorming. If you dig a bit in DB.pas unit you will discover that:
  • TParams collection is not by any means depended by any object such as a query or a stored procedure
  • Further looking at it's constructor we discover that it can be instantiated as an independed object
  • There is also a constructor that needs no owner
  • TParam can hold runtime data for almost all Delphi data types
  • Data in TParam can be accessed by name much like using a TDataset fields. Just take a look at TParams.FindParam, ParamByName, ParamValues and TParam.AsXXX properties …
  • And of course TParams can hold a collection of TParam items much like a single dataset record... ;)
Let's consider some possible scenarios that i faced many times in my life as a developer programming in Delphi and long ago in COBOL!

In real world data applications there are many times that you need to keep a single database record field values in a temp storage for later use. Or perform coded calculations in a set of database records, where you need to hold and access the calculated values at any step during the code execution line. Or perform various computations and/or validations on a set of mutually related records simultaneously...

TParam and TParams collection can do a lot for you in such situations without the need of hard coding individual variables or complex arrays and structures. Another possible usage can be for storing and accessing application parameters, which as you will see in next article, it is very interesting simple when comes to persistence...

The possibilities are endless as i have discovered through the years working with this small but amazing piece of Delphi and i would like to share this experience via this series of articles.

A Note: Of course kind of same functionality could be achieved via TClientDataset, but there are differences, and not to mention the Midas lib overhead. After all TClientDataset is another Delphi's success story by a different point of view and usability and i hope to create a new article series in the future about how i utilize it. And believe me there are numerous ways too!

So, let the journey commence...
The journey starts from the simplest alternate way of using TParam and TParams and somewhere at the end of this article series will be addressing object oriented database manipulation...!

First of all let's see how can we use (the simplest form of using) TParams as a placeholder for the field values of a single database record. Field definitions from a fields collection is used to create or update TParam items in a TParams collection:
procedure FieldsToParams(Fields: TFields; Params: TParams; doAdd: Boolean=False);
var i: integer;
begin
  if not doAdd then Params.Clear;
  for i:=0 to Fields.Count-1 do
   if not (Fields[i].DataType in ObjectFieldTypes) then
    Params.CreateParam(Fields[i].DataType, Fields[i].FieldName, ptUnknown);
end;
The second function is devoted to COBOL's powerfull statement MOVECORR and as it's name suggest assigns (moves) Param values from a TParams collection to their corresponding by name fields in a given Dataset, updating the current record.
function MoveCorr(Params: TParams; Dataset: TDataset): integer;
var i: integer;
    p: TParam;
begin
  Result := 0;
  with Dataset do
  begin
  for i := 0 to FieldCount -1 do
   if (Fields[i].FieldKind = fkData) and (not Fields[i].ReadOnly) then
    begin
    p := Params.FindParam(Fields[i].FieldName);
    if Assigned(p) then //fieldparam may not exists!
      if p.Bound then
      {check for equal fields - problem on ado master/detail when a masterfield changes the detail is requeryed!}
      if not VarEquals(Fields[i].Value, p.Value) then
       begin
       if VarIsEmpty(p.Value) or VarIsNull(p.Value) then
         Fields[i].Clear
       else
         Fields[i].Value := p.Value;
       Inc(Result);
       end;
    end;
  end;
end;
In order for "MoveCorr" to work you will need the following function "VarEquals" that checks if two variants are equal and can handle variant arrays also. Of course you can modify everything as your needs.
{Bonus – Helper function that checks if two variants are equal}
function VarEquals(const V1, V2: Variant; CheckAsString: Boolean): Boolean;
var k,i1,i2,j1,j2: integer;
begin
  Result := False;
  if VarIsArray(V1) or VarIsArray(V2) then
     begin
     if not (VarIsArray(V1) and VarIsArray(V2)) then Exit;
     i1:=VarArrayLowBound(V1,1); j1:=VarArrayHighBound(V1,1);
     i2:=VarArrayLowBound(V2,1); j2:=VarArrayHighBound(V2,1);
     if (j1-i1) <> (j2-i2) then Exit;
     k := j1-i1;
     while k >=0 do begin
      if not VarEquals(V1[i1+k], V2[i2+k]) then Exit;
      Dec(k);
      end;
     Result := True;
     end
  else
  if VarIsNull(v1) then Result := VarIsNull(v2)
  else
  if VarIsNull(v2) then Result := VarIsNull(v1)
  else
  if VarIsEmpty(v1) then Result := VarIsEmpty(v2)
  else
  if VarIsEmpty(v2) then Result := VarIsEmpty(v1)
  else
  try
    if CheckAsString then
       Result := ( VarToStr(V1) = VarToStr(V2) )
    else
    Result := ( V1 = V2 );
  except
  end;
end;
Now we have two basic procedures to transfer field data from a TDataset record to a TParams collection and vice versa. Just thought how easy it is to implement a simple Ditto function on a dataset by using the above procedure/function…
procedure DittoRecord(aDataset: TDataset);
var tmpParams: TParams;
begin
  {Create the temp storage}
  tmpParams := TParams.Create;
  try
    {Copy field data to temp storage}
    FieldsToParams(aDataset.Fields,tmpParams);
    {Append a new record to the dataset}
    aDataset.Append;
    {Fill field values from temp storage}
    MoveCorr(tmpParams,aDataset);
    {…you may need to fixup some field values like keys…}
    {Post newly appended record}
    aDataset.Post;
  finally
   FreeAndNil(tmpParams);
  End;
end;
The above code fragments are directly from my code libraries and include also some of the comments i have done. Feel free to modify the above code as per your needs and if you make any enhancements please contact me.