Reputation: 143
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
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
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