How to add calculated or lookup field to a dataset?

The offical for ZeosLib 7.3 Report problems, ask for help, post proposals for the new version of Zeoslib 7.3/v8
Quick Info:
-We made two new drivers: odbc(raw and unicode version) and oledb
-GUID domain/field-defined support for FB
-extended error infos of Firebird
-performance ups are still in queue
In future some more feature will arrive, so stay tuned and don't hassitate to help
Post Reply
User avatar
aehimself
Zeos Dev Team
Zeos Dev Team
Posts: 797
Joined: 18.11.2018, 17:37
Location: Hungary

How to add calculated or lookup field to a dataset?

Post by aehimself »

I have a TZQuery object with a simple query... SELECT * FROM MyTable.
I want add an extra calculated (or lookup) so I can build it's value runtime based on the data in the other fields of the same record.

Doubleclick on the query, add a field, set the type to calculated and then open the query.
Only one column exists, the calculated one which I just added design-time.

Because of

ZAbstractRODataSet.pas : 3735 (TZAbstractRODataset.InternalOpen)

Code: Select all

    if ((FieldOptions.AutoCreateMode <> acExclusive) or not (lcPersistent in Fields.LifeCycles)) and not FRefreshInProgress then
the call to CreateFields never happens but even if I call it nothing gets done because a similar check exists in Data.DB:

Code: Select all

  if Fields.Count <> 0 then
    case FieldOptions.AutoCreateMode of
      acExclusive:
        Exit;
I guess I'm doing something wrong, how exactly can I append a calculated field right next to the ones returned by the query itself?
Delphi 12.2, Zeos 8 from latest GIT snapshot
Using:
- MySQL server 8.0.18; libmysql.dll 8.0.40 x64 5.7.19 x68, libmariadb.dll 3.3.11
- Oracle server 11.2.0, 12.1.0, 19.0.0; oci.dll 21.15
- MSSQL 2012, 2019; sybdb.dll FreeTDS_3102
- SQLite 3.47
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1956
Joined: 17.01.2011, 14:17

Re: How to add calculated or lookup field to a dataset?

Post by marsupilami »

Hello AEhimself,

usually Delphi expects you to create all fields during design time for these cases. Doing this during runtime is a 3 step process:
  • Create the FieldDefs
  • Create Fields
  • Add Lookup / Calculated Fields
  • Open the DataSet
This is a sample code:

Code: Select all

procedure TSomeForm.SomeProc;
begin
  // probably some code...
  
  // add the lookupfield
    if ZQ_Provision.FieldCount = 0 then
      AddLookupField(ZQ_Provision, 'MA', frmDatenmodul.MitarbeiterQ, 'MITARBEITER_NR', 'NR', 'MITARBEITER');
    ZQ_Provision.Open;
        
  // more code...
end;

procedure AddLookupField(DataSet: TDataSet; const FieldName: String;
  LookupDataSet: TDataSet; const KeyFields, LookupKeyFields, LookupResultField: string);
var
  x: Integer;
  NewField: TWideStringField;
  SourceField: TField;
begin
  SourceField := LookupDataSet.FindField(LookupResultField);
  if not Assigned(SourceField) then raise Exception.Create('Couldn''t find field "' + LookupResultField + '" in LookupDataSet');
  if not (SourceField is TStringField) and not (SourceField is TWideStringField) then raise Exception.Create('Source field needs to be either TStringField or TWideStringField.');

  if (DataSet.FieldDefs.Count = 0) and (DataSet.FieldCount = 0) then begin
    DataSet.FieldDefs.Update;
  end;

  if (DataSet.FieldCount = 0) then begin
    for x := 0 to DataSet.FieldDefs.Count - 1
    do DataSet.FieldDefs.Items[x].CreateField(DataSet);
  end;

  NewField := TWideStringField.Create(DataSet);
  NewField.FieldName := FieldName;
  NewField.KeyFields := KeyFields;
  NewFIeld.LookupDataSet := LookupDataSet;
  NewField.LookupKeyFields := LookupKeyFields;
  NewField.LookupResultField := LookupResultField;
  if Pos(';', LookupResultField) = 0 then NewField.Size := LookupDataSet.FieldByName(LookupResultField).Size;
  NewField.FieldKind := fkLookup;
  NewField.Dataset := DataSet;
  NewField.Size := SourceField.Size;
end;
The steps are all done by AddLookupField. I am not sure, why SourceField needs to be TStringField or TWideStringField. Probably because I use strings for IDs in my program. It possibly also could work for INtegers and the like but I don't need that.

Also you have to make sure that you call AddLookupField only before opening the query for the first time. The fields will not be cleared after in Close when Fields get added. Possibly because TDataSet thinks that someone added Lookupfields manually.

I really wish we had better possibilities for this kind of things in Zeos...

Best regards,

Jan
marsupilami
Platinum Boarder
Platinum Boarder
Posts: 1956
Joined: 17.01.2011, 14:17

Re: How to add calculated or lookup field to a dataset?

Post by marsupilami »

Note: I seem to remember that there are problems when doing a locate on a calculated field or filtering by calculated fields or something like that with the current Zeos 8.0 Beta...
Post Reply