Delphi 加载现有数据时向FDMemTable添加新字段

Delphi 加载现有数据时向FDMemTable添加新字段,delphi,firedac,fdmemtable,Delphi,Firedac,Fdmemtable,我正在使用TFDMemTable,我已经创建了一个数据集,并用数据填充了我的表,然后使用FDMemTable.saveToFile来保存我的数据。 现在的问题是,如何向已保存的数据中添加新的字段,并用默认值填充所有记录? 我尝试将新的字段添加到FDMemTable中,然后加载信息,希望它能使用FieldName自动填充每个字段,并在新字段中添加一个空格,但我收到一个错误提示: `--------------------------- 调试器异常通知 Project Project1.exe引发异

我正在使用
TFDMemTable
,我已经创建了一个数据集,并用数据填充了我的表,然后使用
FDMemTable.saveToFile
来保存我的数据。
现在的问题是,如何向已保存的数据中添加新的
字段
,并用默认值填充所有记录?
我尝试将新的
字段
添加到
FDMemTable
中,然后加载信息,希望它能使用
FieldName
自动填充每个字段,并在新字段中添加一个空格,但我收到一个错误提示: `---------------------------

调试器异常通知 Project Project1.exe引发异常类EDatabaseError,消息为“Field”插曲“not found”。 中断继续帮助 `
我怎样才能解决这个问题?是否有一种解决方法,可以将具有默认值的新字段添加到现有数据中?
下面是一个测试用例:

// 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(基于维多利亚的回答):

//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)。请注意,在将字段添加到字段集合时,必须关闭数据集

因此,从文件加载数据集后立即关闭数据集,添加字段并再次打开。

从文件加载数据集后添加该字段(而不是字段定义)(假设siMeta包含在的属性中)。请注意,在将字段添加到字段集合时,必须关闭数据集


因此,在从文件加载后立即关闭数据集,添加字段并再次打开它。

下面的代码在Delphi Seattle中适用。它紧密地基于您的,但有一些小的变化(见评论)和一个重要的补充

问题是,如果您仔细观察
FDMemTable1.loadFromFile
,它实际上会清除字段defs/字段,因此一开始没有太多的意义再次设置它们,因此您添加的
插曲
字段将从加载的数据集中被忽略

为了避免这种情况,我添加了一个临时TFDMemTable,将XML文件加载到该表中,然后使用
CopyDataSet
将其内容复制到FDMemTable1。FDMemTable1在流程中保留添加的插曲字段,当然,一旦调用
CopyDataSet
,您可以添加代码来设置插曲字段数据

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;
程序TForm1.AddFieldTest;
变量
DataFN:字符串;
TempMemTable:TFDMemTable;
开始
//添加,以避免数据文件名的相对路径
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;
//我用一些值填充表格
FDMemTable1.打开;
FDMemTable1.追加记录([1,'电影1',1]);
FDMemTable1.追加记录([2'电影2',2]);
FDMemTable1.追加记录([3'电影3',1]);
//看到网格上的值后,我按下一个按钮并将表保存为XML
FDMemTable1.saveToFile(DataFN);
//添加,关闭数据集并清除FieldDefs
//如果没有FieldDefs.Clear调用,代码将生成“重复字段ID”错误
表1.关闭;
FDMemTable1.FieldDefs.Clear;
//现在,在关闭程序并再次运行它之后,我想使用名为“插曲”的新FieldDef加载数据,默认值为0
//该表连接到cxGrid,当我尝试加载时,我得到了我提到的错误。
FDMemTable1.FieldDefs.Add('ID',ftInteger,0,false);
FDMemTable1.FieldDefs.Add('name',ftString,30,false);
//这条线是新的
FDMemTable1.FieldDefs.Add('eposion',ftInteger,0,false);
FDMemTable1.FieldDefs.Add('QualityID',ftInteger,0,false);
FDMemTable1.CreateDataSet;
//检查字段计数和事件字段的存在
标题:=IntToStr(FDMemTable1.FieldCount);
断言(FDMemTable1.FindField(‘插曲’)Nil);
//创建临时TFDMemTable
TempMemTable:=TFDMemTable.Create(Nil);
尝试
//将数据加载到临时TFDMemTable中
TempMemTable.loadFromFile(DataFN);
//将临时TFDMemTable中的数据复制到FDMemTable1中
FDMemTable1.CopyDataSet(TempMemTable,[coAppend]);
//检查字段计数和事件字段的存在
标题:=IntToStr(FDMemTable1.FieldCount);
断言(FDMemTable1.FindField(‘插曲’)Nil);
最后
TempMemTable.Free;
结束;
结束;

下面的代码在德尔福西雅图很适合我。它紧密地基于您的,但有一些小的变化(见评论)和一个重要的补充

问题是,如果您仔细观察
FDMemTable1.loadFromFile
,它实际上会清除字段defs/字段,因此一开始没有太多的意义再次设置它们,因此您添加的
插曲
字段将从加载的数据集中被忽略

为了避免这种情况,我添加了一个临时TFDMemTable,将XML文件加载到该表中,然后使用
CopyDataSet
将其内容复制到FDMemTable1。FDMemTable1在流程中保留添加的插曲字段,当然,一旦调用
CopyDataSet
,您可以添加代码来设置插曲字段数据

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;
程序TForm1.AddFieldTest;
变量
DataFN:字符串;
TempMemTable:TFDMemTable;
开始
//添加,以避免数据文件名的相对路径
DataFN:=ExtractFi