Search code examples
delphitclientdataset

Setting up ADT fields in code


I'm experimenting with a simple ClientDataSet project that uses a TADTField named Address which contains two subfields, Line1 and City, both of which are strings, size 20. THe CDS is connected to a DBGrid and DBNavigator.

If I set up the CDS using TFieldDefs in the Object Inspector and the ChildDefs property of the ADT field, the project compiles and executes fine.

However, if I try to set up the ATD field and its children in code, I get two problems:

  • Unlike when I use the FieldDefs method, the ATD "cell" doesn't appear in the DBGrid, so the Line1 and City sub-fields dont display inside it. Instead they appear as ordinary fields and they are duplicated. There is one "Line1" column, then a "City" one, then another "Line1" ...

  • When I close the form, I get a "double-free" AV inside a second (?) call to TFields.Destroy.

Obvioulsly I'm doing something wrong but I can't see what it is.

Here's my code :

procedure TForm1.FormCreate(Sender: TObject);
var
  ADTField : TADTField;
  Field : TField;
begin
  // at this point, the clientDataSet has no TFields or TFieldDefs 
  Field := TIntegerField.Create(nil);
  Field.FieldName := 'ID';
  Field.DataSet := ClientDataset1;

  ADTField := TADTField.Create(nil);
  ADTField.FieldName := 'Address';
  ADTField.DataSet := ClientDataset1;

  Field := TStringField.Create(nil);
  Field.FieldName := 'Line1';
  Field.Size := 20;
  Field.DataSet := ClientDataset1;
  ADTField.Fields.Add(Field);

  Field := TStringField.Create(nil);
  Field.FieldName := 'City';
  Field.Size := 20;
  Field.DataSet := ClientDataset1;
  ADTField.Fields.Add(Field);

  ClientDataset1.CreateDataSet;
  ClientDataset1.Insert;
  ClientDataset1.FieldByName('ID').AsInteger := 1;
  try
    ADTField.Fields.FieldByName('Line1').AsString := '1, Railway Cuttings';
    ADTField.Fields.FieldByName('City').AsString := 'London';
  except
  end;
  ClientDataset1.Post;
end;

That's the entire code of the project. I'm using D7.


Solution

  • I remember being foxed by something similar when I first tried out ADT fields: although the TFieldDefs editor in the IDE has an obvious way to add child FieldDefs to an TADTField, there's no counterpart in the IDE's TFields editor.

    Anyway, I think you're not quite "parenting" the two fields that you want to be children of the ADT one correctly. Instead of calling ADTField.Fields.Add, you need to do it via the field itself, by setting its ParentField property:

      Field := TStringField.Create(ClientDataset1);
      Field.FieldName := 'Line1';
      Field.Size := 20;
      Field.DataSet := ClientDataset1;
    //  ADTField.Fields.Add(Field);
      Field.ParentField := ADTField;
    

    And that btw is how you would do it in the IDE if you were setting up TFields instead of TFieldDefs. You'd create your Line1 and City fields in the ordinary way using the TFields editor, then select them in turn on the OI and set their ParentField property. I think you'll find that they and the Address field will then display in your grid correctly and the AV on shutdown will go away.