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.
在使用LoadFromFile后,我无法在TClientDataSet中更改fielddef的大小。有没有人有一个很好的方法来改变给定ClientDataSet的大小,但仍保留所有其他东西。
2 个解决方案
#1
You can create a new dataset, using the old dataset's FieldDefs The key point is TFieldDefs.Assign
. Here's a small example:
您可以使用旧数据集的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;
#2
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.
实现TDataSet的方式有虚拟方法来分配和释放记录缓冲区,以及从该缓冲区获取和设置值。大多数数据集后代为缓冲区保留一块连续内存,因此如果您的三个字段长度为4,6和20个字节,则字段1将从位置0开始,字段2从位置4开始,字段3从位置10开始。
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.
解决这个问题的方法是将您的内容从原始CDS复制到具有不同字段大小的新内容。按值分配值,或使用TDataSetProvider。如果使用提供程序(最佳方法)并且您不知道确切的定义,则仍需要迭代源数据集字段并将其添加到具有正确大小的目标。
#1
You can create a new dataset, using the old dataset's FieldDefs The key point is TFieldDefs.Assign
. Here's a small example:
您可以使用旧数据集的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;
#2
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.
实现TDataSet的方式有虚拟方法来分配和释放记录缓冲区,以及从该缓冲区获取和设置值。大多数数据集后代为缓冲区保留一块连续内存,因此如果您的三个字段长度为4,6和20个字节,则字段1将从位置0开始,字段2从位置4开始,字段3从位置10开始。
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.
解决这个问题的方法是将您的内容从原始CDS复制到具有不同字段大小的新内容。按值分配值,或使用TDataSetProvider。如果使用提供程序(最佳方法)并且您不知道确切的定义,则仍需要迭代源数据集字段并将其添加到具有正确大小的目标。