I'm having trouble to change size of fielddefs in a TClientDataSet after i use LoadFromFile. Does anybody have a good way to change the size of a given ClientDataSet but still keep all the other things.
The way the TDataSet is implemented, there are virtual methods to allocate and free the record buffer and also to get and set values from that buffer. Most dataset descendants keep a block of contiguous memory for the buffer, so if your three fields are four, six and twenty bytes in length, field 1 will start at position 0, field 2 at position four and field 3 at position ten.
If you want to change a field size while the dataset is open, all those buffers must be resized and adjusted or you'll run into trouble. There is no virtual method to resize the buffer, so I'd say it is probably not doable.
The way to go about this, is to copy your content from the original CDS to a new one with different field sizes. Assign it value by value, or use a TDataSetProvider. If you use the provider (best approach) and you don't know the exact definition, you'll need to still iterate through the source dataset fields and add them to the destination with the correct size.
You can create a new dataset, using the old dataset's FieldDefs The key point is TFieldDefs.Assign
. Here's a small example:
// insert test data
procedure TForm1.InsertRecord(DataSet: TDataSet; ID: Integer; const Name: string);
begin
DataSet.Insert;
try
DataSet.Fields[0].AsInteger := ID;
DataSet.Fields[1].AsString := Name;
DataSet.Post;
except
DataSet.Cancel;
raise;
end;
end;
// create the original dataset
procedure TForm1.Button1Click(Sender: TObject);
var
DataSet: TClientDataSet;
begin
DataSet := TClientDataSet.Create(nil);
try
DataSet.FieldDefs.Add('ID', ftInteger);
DataSet.FieldDefs.Add('NAME', ftString, 20);
DataSet.CreateDataSet;
DataSet.LogChanges := False;
InsertRecord(DataSet, 1, 'Hello');
InsertRecord(DataSet, 2, 'World!');
DataSet.SaveToFile(ExtractFilePath(Application.ExeName) + 'old.xml', dfXML);
finally
DataSet.Free;
end;
end;
// create the new dataset
procedure TForm1.Button2Click(Sender: TObject);
var
OldDataSet, NewDataSet: TClientDataSet;
begin
OldDataSet := nil;
NewDataSet := nil;
try
OldDataSet := TClientDataSet.Create(nil);
OldDataSet.LoadFromFile(ExtractFilePath(Application.ExeName) + 'old.xml');
NewDataSet := TClientDataSet.Create(nil);
NewDataSet.FieldDefs.Assign(OldDataSet.FieldDefs);
NewDataSet.FieldDefs[1].Size := 30;
NewDataSet.CreateDataSet;
NewDataSet.LogChanges := False;
OldDataSet.First;
while not OldDataSet.EOF do
begin
InsertRecord(NewDataSet, OldDataSet.Fields[0].AsInteger, OldDataSet.Fields[1].AsString);
OldDataSet.Next;
end;
NewDataSet.SaveToFile(ExtractFilePath(Application.ExeName) + 'new.xml', dfXML);
finally
OldDataSet.Free;
NewDataSet.Free;
end;
end;