Gary Shelton
Gary Shelton

Reputation: 143

How to set TClientDataSet field names and displayName

Delphi 10.3

I'm trying to setup a TClientDataSet to use in my tests, but after adding the fields the Name and DisplayText properties are empty, and the DisplayLabel property has the FieldName property.

class function TTestDataSetFactory.CreateTrainingCategoriesDataSet: TDataSet;
var
    DS : TClientDataSet;
    FMaxID : TAggregate;
begin
    DS := TClientDataSet.Create(nil);
    DS.Name := 'training_categories';

    with DS.FieldDefs do
    begin
        Add('id', ftInteger, 0, True);
        Add('category', ftString, 50, True);
        Add('description', ftString, 50, False);
    end;


    //Create function adds the aggregate to the DataSet. No more action needed
    FMaxID := TAggregate.Create(DS.Aggregates, DS);
    FMaxID.Expression := 'Max(id)';
    FMaxID.Active := True;
    FMaxID.Visible := True;
    FMaxID.DisplayName := 'MaxID';
    FMaxID.AggregateName := 'max_id';

    DS.CreateDataSet;

  DS.StoreDefs := True;

  DS.Open;

  DS.Fields[0].Name := 'id';
  DS.Fields[1].Name := 'category';
  DS.Fields[2].Name := 'description';

  DS.Fields[0].DisplayLabel := 'ID';
  DS.Fields[1].DisplayLabel := 'Category';
  DS.Fields[2].DisplayLabel := 'Description';

    DS.AggregatesActive := True;
    DS.Close;
    //Setup AutoInc, performed in AfterInsert event, with ID field (0)
    DS.AfterInsert := IncIdAtIndex0;
    Result := DS;
end;

Just a quick test:

procedure TTestDataSetFactoryTest.CreateTrainingCategoriesDataSet_ReturnsCorrectDataSet;
var
  DS : TDataset;
begin
  DS := TTestDataSetFactory.CreateTrainingCategoriesDataSet;
  DS.Open;

  CodeSite.Send( Format('Field 0 DisplayLabel = %s',[DS.Fields[0].DisplayLabel]) );
  CodeSite.Send( Format('Field 0 Name = %s',[DS.Fields[0].Name]) );
  CodeSite.Send( Format('Field 0 DisplayText = %s',[DS.Fields[0].DisplayText]) );

  Assert.AreEqual(3, DS.Fields.Count);

  Assert.AreEqual('id', DS.Fields[0].Name);
  Assert.AreEqual('category', DS.Fields[1].Name);
  Assert.AreEqual('description', DS.Fields[2].Name);

  Assert.AreEqual('ID', DS.Fields[0].DisplayName);
  Assert.AreEqual('Category', DS.Fields[1].DisplayName);
  Assert.AreEqual('Description', DS.Fields[2].DisplayName);

  DS.Close;
end;

The Assert.AreEqual(3, DS.Fields.Count); passes but all Name and DisplayText properties fail.

Field[0] logs this

Field 0 DisplayLabel = id

Field 0 Name =

Field 0 DisplayText =

Adding the field property assignments into the test everything passes, so the fields are present.

Does anyone know why the field properties are not set in the Dataset creation? The fields are there. The assigned name of the DataSet is fine also.

Thanks in advance

Gary

Upvotes: 1

Views: 1979

Answers (2)

MartynA
MartynA

Reputation: 30715

FPiette has given you a fine and up-to-date (using the fairly recent TField.LifeCycle) answer to creating TFields from TFieldDefs. I just want to mention an alternative which does not require the use of TFieldDefs.

As a TDataSet is opened, its BindFields method is called, which "connects" its collection of TFields with the field buffers which store the records read from the datafile. If the fields do not already exist, they are created at the time, but if they do, there is not need to create them.

What this means is that very simple code like the following is all that is required to create and use the DataSet's TFields. The simple step of creating the TFields with a persistent owner - in the example, the form - ensures that they last for the lifetime of their Owner. That's how persistent TFields created in the IDE using the Fields editor (invoked by double-clicked the DataSet's icon) work.

procedure TForm1.FormCreate(Sender: TObject);
var
  AField : TField;
begin
  AField := TIntegerField.Create(Self);
  AField.FieldKind := fkData;
  AField.FieldName := 'ID';
  AField.DataSet := ClientDataSet1;

  AField := TStringField.Create(Self);
  AField.FieldKind := fkData;
  AField.FieldName := 'AValue';
  AField.DataSet := ClientDataSet1;

  ClientDataSet1.CreateDataSet;

  ClientDataSet1.InsertRecord([1, 'One']);
  ClientDataSet1.InsertRecord([2, 'Two']);
  ClientDataSet1.InsertRecord([3, 'Three']);
end;

Upvotes: 2

fpiette
fpiette

Reputation: 12292

You have to assign lcPersistent to the LifeCycle property like this:

DS.Fields[0].LifeCycle    := lcPersistent;
DS.Fields[0].Name         := 'id';
DS.Fields[0].DisplayLabel := 'ID';

And of course do the same with all fields.

Warning: The field property name must be unique because it is used as component name which must be unique. You should probably construct it with dataset name combined.

Upvotes: 4

Related Questions