在使用LoadFromFile后,我无法在TClientDataSet中更改fielddef的大小。 有没有人有一个很好的方法来改变给定ClientDataSet的大小,但仍保留所有其他东西。
答案 0 :(得分:3)
实现TDataSet的方式有虚拟方法来分配和释放记录缓冲区,以及从该缓冲区获取和设置值。大多数数据集后代为缓冲区保留一块连续内存,因此如果您的三个字段长度为4,6和20个字节,则字段1将从位置0开始,字段2从位置4开始,字段3从位置10开始。
如果要在数据集打开时更改字段大小,则必须调整所有这些缓冲区的大小并进行调整,否则您将遇到麻烦。没有虚拟方法来调整缓冲区的大小,所以我认为它可能不可行。
解决此问题的方法是将您的内容从原始CDS复制到具有不同字段大小的新内容。按值分配值,或使用TDataSetProvider。如果您使用提供程序(最佳方法)并且您不知道确切的定义,则仍需要迭代源数据集字段并将其添加到具有正确大小的目标。
答案 1 :(得分:1)
您可以使用旧数据集的FieldDef创建新数据集关键点为TFieldDefs.Assign
。这是一个小例子:
// 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;