delphifiredacin-memory-tablesmemory-tablefdmemtable

How to change Delphi FireDAC tFDMemTable field name in design-time


I try to change the field name of FDMemTable1field1 which is 'field1' to 'field3'. There is no code and all is done in design-time.

TForm1 = class(TForm)
  DBGrid1: TDBGrid;
  DataSource1: TDataSource;
  FDMemTable1: TFDMemTable;
  FDMemTable1field1: TStringField;
  FDMemTable1field2: TStringField;

When a file is loaded via FDMemTable1 pop-up menu in design window DBGrid1 shows data well. Changing 'field1' to 'field3' in Object Inspector makes FDMemTable1.Active 'false' and all cells of DBGrid1 clear.

Switching FDMemTable1.Active 'true' shows only DBGrid1 title 'field3' and 'field2' not data cells.

At last loading the same file fires an error Field 'field3' not found. Even if I change the name after the deactivation of FDMemTable1 the result is same.

Is changing a field name in design-time possible? Should I copy the whole 'field1' to 'field3' and delete the former in run-time?


Solution

  • I think that a problem with what you want is that afaik you can't rename a field in an FDMemTable while it has data stored in it, because the field name is amongst the metadata stored in the saved data.

    That said, here's a minimal example of renaming an FDMemTable field without having to discard the data stored in it. Basically, it writes the table's data out in XML format, changes the field name (in this case 'FieldA') to something different ('FieldB') and reloads the data from the changed XML file.

    uses [...] FireDAC.Stan.StorageXML;
    
    type
      TForm1 = class(TForm)
        FDMemTable1: TFDMemTable;
        DataSource1: TDataSource;
        DBGrid1: TDBGrid;
        Button1: TButton;
        FDStanStorageXMLLink1: TFDStanStorageXMLLink;
        procedure FormCreate(Sender: TObject);
      public
      end;
    
    [...]
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      AFileName : String;
      TL : TStringList;
      S : String;
    begin
      AFileName := 'C:\Temp\XMLData.XML';
    
      FDMemTable1.SaveToFile(AFileName, sfXML);
      TL := TStringList.Create;
      try
        TL.LoadFromFile(AFileName);
        FDMemTable1.Close;
    
        TL.Text := StringReplace(TL.Text, 'FieldA', 'FieldB', [rfReplaceAll]);
        TL.SaveToFile(AFileName);
    
        DBGrid1.Columns.Clear;
        FDMemTable1.FieldDefs.Clear;
        FDMemTable1.Fields.Clear;
        FDMemTable1.LoadFromFile(AFileName, sfXML);
      finally
        TL.Free;
      end;
    end;
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      Link : TFDStanStorageXMLLink;  //  This is needed to reload the data in XML format
      AField : TField;
    begin
    
      Link := TFDStanStorageXMLLink.Create(Self);
    
      AField := TIntegerField.Create(Self);
      AField.FieldName := 'ID';
      AField.DataSet := FDMemTable1;
    
      AField := TStringField.Create(Self);
      AField.FieldName := 'FieldA';
      AField.Size := 32;
      AField.DataSet := FDMemTable1;
    
      FDMemTable1.CreateDataSet;
    
      FDMemTable1.InsertRecord([1, 'One']);
      FDMemTable1.InsertRecord([2, 'Two']);
    end;
    

    Obviously, if you didn't want to write the data to the filesystem, you could use a temporary stream and the FDMemTable's SaveToStream and LoadFromStream.