How can I add fields to a clientdataset at runtime?
Asked Answered
B

5

13

I have a TClientDataSet, which is provided by a TTable’s dataset. The dataset has two fields: postalcode (string, 5) and street (string, 20)

At runtime I want to display a third field (string, 20). The routine of this field is getting the postalcode as a parameter and gives back the city belongs to this postalcode.

The problem is only about adding a calculated field to the already existing ones. Filling the data itself is not the problem.

I tried:

  cds.SetProvider(Table1);
  cds.FieldDefs.Add('city', ftString, 20);

  cds.Open;

  cds.Edit;
  cds.FieldByName('city').AsString := 'Test';  // --> errormessage (field not found)
  cds.Post;

cds is my clientdataset, Table1 is a paradox Table, but the problem is the same with other databases.

Thanks in advance

Bigener answered 8/2, 2011 at 14:15 Comment(1)
similary to my questionIncentive
P
27

If you want to add additional fields other than those exist in the underlying data, you need to also add the existing fields manually as well. The dataset needs to be closed when you're adding fields, but you can have the necessary metadata with FieldDefs.Update if you don't want to track all field details manually. Basically something like this:

var
  i: Integer;
  Field: TField;
begin    
  cds.SetProvider(Table1);

  // add existing fields
  cds.FieldDefs.Update;
  for i := 0 to cds.FieldDefs.Count - 1 do 
    cds.FieldDefs[i].CreateField(cds);

  // add calculated field
  Field := TStringField.Create(cds);
  Field.FieldName := 'city';
  Field.Calculated := True;
  Field.DataSet := cds;

  cds.Open;
end;


Also see this excellent article by Cary Jensen.

Pridgen answered 8/2, 2011 at 15:6 Comment(1)
Thank you for the answer and the nice link, ill try this, although ill have have to add all the fileds in my sql manually.Bigener
B
6

Well i found a simpler solution, as i have 24 fields in my sql i didnt wanted to add them all manually so i added a dummy field to the sql statement instead like:

select '      ' as city, the rest of the fields ... 

which i can modify in my program OnAfterOpen event.

Well i had to define in the sql how long that field should be by leaving enough empty spaces, for instance 5 empty spaces for 5 characters, so i must know how long the city name could be.

Bigener answered 9/2, 2011 at 8:49 Comment(1)
This might not look elegant, but it is really easy to implement.Cavender
A
4

You should use CreateDataset after add field:

cds.SetProvider(Table1);
cds.FieldDefs.Add('city', ftString, 20);
cds.CreateDataset; 

cds.Open;
cds.Edit;
cds.FieldByName('city').AsString := 'Test';  
cds.Post;
Audible answered 13/5, 2015 at 10:27 Comment(0)
C
3

Would like to share more accurate Query for unexisting fields. I bet it's better to use cast, neither spaces!

select E.NAME, E.SURNAME, cast(null as varchar(20)) as CITY
from EMPLOYEE E

e.g. | Marc'O | Polo | <NULL> |

It's more accurate, can definetly see field size, understandable, easy, safe!

Cupp answered 6/6, 2014 at 11:37 Comment(0)
T
1

if you want to combine already existing "dynamic" data fields (from provider side) with additional client side persistent fields (calculated, lookup, internalcalc, aggregate) you should subclass CDS. just introduce extra boolean property CombineFields and either override BindFields (in newer delphi versions) or the entire InternalOpen (as I did in d2006/2007) with the following line

if DefaultFields or CombineFields then CreateFields; { TODO -ovavan -cSIC : if CombineFields is true then persistent fields will coexist with Default ones }

that will allow you to avoid all that runtime mess with FieldDefs/CreateField

Tachistoscope answered 28/4, 2012 at 7:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.