加载现有数据时向 FDMemTable 添加新字段
Adding a new Field to FDMemTable when loading an existing data
我正在使用 TFDMemTable
,我创建了一个数据集并用数据填充了我的 table,然后使用 FDMemTable.saveToFile
保存了我的数据。
现在的问题是,我如何向这个已保存的数据添加一个新的 Field
并用默认值填充所有记录?
我尝试将新的 Field
添加到 FDMemTable
,然后加载信息,希望它会使用它的 FieldName
自动填充每个字段,并使用空的 space 填充新字段,但是我收到一条错误消息:
`-------------------------
调试器异常通知
项目 Project1.exe 引发异常 class EDatabaseError,消息为“未找到字段 'Episode'”。
中断继续帮助
`
我怎样才能解决这个问题 ?是否可以解决向现有数据添加具有默认值的新字段?
这是一个测试用例:
// here is a simple example, i have a few fields
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// i fill the the table with some value
FDMemTable1.Open;
FDMemTable1.AppendRecord([1, 'Movie1', 1]);
FDMemTable1.AppendRecord([2, 'Movie2', 2]);
FDMemTable1.AppendRecord([3, 'Movie3', 1]);
// after seeing the value on the grid, i push a button and save the table as XML
FDMemTable1.saveToFile('Data.xml');
// now after closing the program and running it again, i want to load the data with a new FieldDef Called Episode with a default value 0
// the table is connected to cxGrid, and the moment i try to load, i get the error i mentioned.
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
// this line is NEW
FDMemTable1.FieldDefs.Add('Episode', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// i try to load but i get an error
FDMemTable1.loadFromFile('Data.xml');
更新 1(基于 Victoria 的回答):
//All the codes below are executed after the code at the top, after the loadFromFile.
FDMemTable1.ResourceOptions.StoreItems := FDMemTable1.ResourceOptions.StoreItems + [siMeta];
FDMemTable1.Close;
//i tried putting FDMemTable1 as the owner but when i try the line "FDMemTable1.Fields.add" i get an Duplicate error!
// and when i try putting nil, i get access violation ! so i tried putting the owner someother random table and it fixed the problem
fieldDefs := TFieldDefs.Create(someRandomFDMemTable);
fieldDefs.Add('Episodes', ftString, 30, false);
FDMemTable1.Fields.Add(fieldDefs.Items[0].CreateField(FDMemTable1));
FDMemTable1.Open;
如你所见,我有两个问题,
1- 我在添加新字段时遇到问题!在出现错误的地方,我首先尝试使用 TFieldDef
而不是 TFieldDefs
,但我无法让它工作。
2- 是不是所有的列都是空的,网格上没有数据。
当我尝试强行解决问题1时出现问题2。
从文件加载数据集后添加该字段(不是字段定义)(假设 siMeta 包含在 StoreItems property of the ResourceOptions of your TFDMemTable 中)。请注意,将字段添加到字段集合时必须关闭数据集。
因此,从文件加载后立即关闭数据集,添加字段并再次打开它。
下面的代码在 Delphi 西雅图适合我。它与您的非常接近,但有一些小的变化(见评论)和一个重要的补充。
事实是,如果你仔细观察 FDMemTable1.loadFromFile
,它实际上清除了 FieldDefs/Fields,所以一开始就重新设置它们没有太多意义,所以你添加了 Episode
字段将从加载的数据集中省略。
为避免这种情况,我所做的补充是使用临时 TFDMemTable,将 XML 文件加载到其中,然后使用 CopyDataSet
将其内容复制到 FDMemTable1。 FDMemTable1在流程中保留了添加的Episode字段,你当然可以在调用CopyDataSet
后添加代码来设置Episode字段数据
procedure TForm1.AddFieldTest;
var
DataFN : String;
TempMemTable : TFDMemTable;
begin
// Added, to avoid relative path for data file name
DataFN := ExtractFilePath(Application.ExeName) + 'Data.Xml';
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// i fill the the table with some value
FDMemTable1.Open;
FDMemTable1.AppendRecord([1, 'Movie1', 1]);
FDMemTable1.AppendRecord([2, 'Movie2', 2]);
FDMemTable1.AppendRecord([3, 'Movie3', 1]);
// after seeing the value on the grid, i push a button and save the table as XML
FDMemTable1.saveToFile(DataFN);
// Added, close the dataset and clear the FieldDefs
// Without the FieldDefs.Clear call, your code produces a "Duplicate field ID" error
FDMemTable1.Close;
FDMemTable1.FieldDefs.Clear;
// now after closing the program and running it again, i want to load the data with a new FieldDef Called Episode with a default value 0
// the table is connected to cxGrid, and the moment i try to load, i get the error i mentioned.
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
// this line is NEW
FDMemTable1.FieldDefs.Add('Episode', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// check the FieldCount and existence of the Episode field
Caption := IntToStr(FDMemTable1.FieldCount);
Assert(FDMemTable1.FindField('Episode') <> Nil);
// Create a temporary TFDMemTable
TempMemTable := TFDMemTable.Create(Nil);
try
// load the data into the temporary TFDMemTable
TempMemTable.loadFromFile(DataFN);
// copy the data from the temporary TFDMemTable into FDMemTable1
FDMemTable1.CopyDataSet(TempMemTable, [coAppend]);
// check the FieldCount and existence of the Episode field
Caption := IntToStr(FDMemTable1.FieldCount);
Assert(FDMemTable1.FindField('Episode') <> Nil);
finally
TempMemTable.Free;
end;
end;
我正在使用 TFDMemTable
,我创建了一个数据集并用数据填充了我的 table,然后使用 FDMemTable.saveToFile
保存了我的数据。
现在的问题是,我如何向这个已保存的数据添加一个新的 Field
并用默认值填充所有记录?
我尝试将新的 Field
添加到 FDMemTable
,然后加载信息,希望它会使用它的 FieldName
自动填充每个字段,并使用空的 space 填充新字段,但是我收到一条错误消息:
`-------------------------
调试器异常通知
项目 Project1.exe 引发异常 class EDatabaseError,消息为“未找到字段 'Episode'”。
中断继续帮助
`
我怎样才能解决这个问题 ?是否可以解决向现有数据添加具有默认值的新字段?
这是一个测试用例:
// here is a simple example, i have a few fields
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// i fill the the table with some value
FDMemTable1.Open;
FDMemTable1.AppendRecord([1, 'Movie1', 1]);
FDMemTable1.AppendRecord([2, 'Movie2', 2]);
FDMemTable1.AppendRecord([3, 'Movie3', 1]);
// after seeing the value on the grid, i push a button and save the table as XML
FDMemTable1.saveToFile('Data.xml');
// now after closing the program and running it again, i want to load the data with a new FieldDef Called Episode with a default value 0
// the table is connected to cxGrid, and the moment i try to load, i get the error i mentioned.
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
// this line is NEW
FDMemTable1.FieldDefs.Add('Episode', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// i try to load but i get an error
FDMemTable1.loadFromFile('Data.xml');
更新 1(基于 Victoria 的回答):
//All the codes below are executed after the code at the top, after the loadFromFile.
FDMemTable1.ResourceOptions.StoreItems := FDMemTable1.ResourceOptions.StoreItems + [siMeta];
FDMemTable1.Close;
//i tried putting FDMemTable1 as the owner but when i try the line "FDMemTable1.Fields.add" i get an Duplicate error!
// and when i try putting nil, i get access violation ! so i tried putting the owner someother random table and it fixed the problem
fieldDefs := TFieldDefs.Create(someRandomFDMemTable);
fieldDefs.Add('Episodes', ftString, 30, false);
FDMemTable1.Fields.Add(fieldDefs.Items[0].CreateField(FDMemTable1));
FDMemTable1.Open;
如你所见,我有两个问题,
1- 我在添加新字段时遇到问题!在出现错误的地方,我首先尝试使用 TFieldDef
而不是 TFieldDefs
,但我无法让它工作。
2- 是不是所有的列都是空的,网格上没有数据。
当我尝试强行解决问题1时出现问题2。
从文件加载数据集后添加该字段(不是字段定义)(假设 siMeta 包含在 StoreItems property of the ResourceOptions of your TFDMemTable 中)。请注意,将字段添加到字段集合时必须关闭数据集。
因此,从文件加载后立即关闭数据集,添加字段并再次打开它。
下面的代码在 Delphi 西雅图适合我。它与您的非常接近,但有一些小的变化(见评论)和一个重要的补充。
事实是,如果你仔细观察 FDMemTable1.loadFromFile
,它实际上清除了 FieldDefs/Fields,所以一开始就重新设置它们没有太多意义,所以你添加了 Episode
字段将从加载的数据集中省略。
为避免这种情况,我所做的补充是使用临时 TFDMemTable,将 XML 文件加载到其中,然后使用 CopyDataSet
将其内容复制到 FDMemTable1。 FDMemTable1在流程中保留了添加的Episode字段,你当然可以在调用CopyDataSet
后添加代码来设置Episode字段数据
procedure TForm1.AddFieldTest;
var
DataFN : String;
TempMemTable : TFDMemTable;
begin
// Added, to avoid relative path for data file name
DataFN := ExtractFilePath(Application.ExeName) + 'Data.Xml';
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// i fill the the table with some value
FDMemTable1.Open;
FDMemTable1.AppendRecord([1, 'Movie1', 1]);
FDMemTable1.AppendRecord([2, 'Movie2', 2]);
FDMemTable1.AppendRecord([3, 'Movie3', 1]);
// after seeing the value on the grid, i push a button and save the table as XML
FDMemTable1.saveToFile(DataFN);
// Added, close the dataset and clear the FieldDefs
// Without the FieldDefs.Clear call, your code produces a "Duplicate field ID" error
FDMemTable1.Close;
FDMemTable1.FieldDefs.Clear;
// now after closing the program and running it again, i want to load the data with a new FieldDef Called Episode with a default value 0
// the table is connected to cxGrid, and the moment i try to load, i get the error i mentioned.
FDMemTable1.FieldDefs.Add('ID', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('name', ftString, 30, false);
// this line is NEW
FDMemTable1.FieldDefs.Add('Episode', ftInteger, 0, false);
FDMemTable1.FieldDefs.Add('QualityID', ftInteger, 0, false);
FDMemTable1.CreateDataSet;
// check the FieldCount and existence of the Episode field
Caption := IntToStr(FDMemTable1.FieldCount);
Assert(FDMemTable1.FindField('Episode') <> Nil);
// Create a temporary TFDMemTable
TempMemTable := TFDMemTable.Create(Nil);
try
// load the data into the temporary TFDMemTable
TempMemTable.loadFromFile(DataFN);
// copy the data from the temporary TFDMemTable into FDMemTable1
FDMemTable1.CopyDataSet(TempMemTable, [coAppend]);
// check the FieldCount and existence of the Episode field
Caption := IntToStr(FDMemTable1.FieldCount);
Assert(FDMemTable1.FindField('Episode') <> Nil);
finally
TempMemTable.Free;
end;
end;