Delphi ClientDataSet - 如何将新数据字段添加到现有数据集?

时间:2016-10-05 19:55:48

标签: delphi tclientdataset

我在解决如何将新数据字段添加到旧数据集文件时遇到问题。例如,旧数据集可能只有ID字段。后来我们决定需要一个ISACTIVE字段。我想重新打开我的仅ID数据,然后在添加了ISACTIVE值的情况下重新保存它。例如:

CDS := TClientDataset.Create(nil);
with TIntegerField.Create(CDS) do
begin
  FieldName := 'ID';
  FieldKind := fkData;
  DataSet := CDS;
end;
CDS.CreateDataSet;

CDS.Close;
with TBooleanField.Create(CDS) do
begin
  FieldName := 'ISACTIVE';
  FieldKind := fkData;
  DataSet := CDS;
end;
CDS.Open; // <--Raises EDatabaseError with message 'Field 'ISACTIVE' not found'.

我查了类似的问题,我发现的最接近的问题是只关注向数据集添加新的计算字段。上述方法适用于添加计算字段。

目前我能想到的唯一(杂乱)解决方案是将仅ID数据加载到临时数据集中,然后创建一个定义了ID和ISACTIVE字段的新数据集,然后遍历仅ID数据集和将记录复制到新数据集。

2 个答案:

答案 0 :(得分:2)

有一种简单的方法可以做到这一点。

如果您的CDS具有整数ID字段和字符串80名称字段,并且您将数据集保存为XML,如

AFileName := 'C:\Temp\CDSData.Xml';
CDS1.SaveToFile(AFileName, dfXML);

生成的XML文件将如下所示(对于D7)

<?xml version="1.0" standalone="yes"?>  
<DATAPACKET Version="2.0">
  <METADATA>
    <FIELDS>
      <FIELD attrname="ID" fieldtype="i4"/>
      <FIELD attrname="Name" fieldtype="string" WIDTH="80"/>
    </FIELDS><PARAMS CHANGE_LOG="1 0 4"/>
  </METADATA>
  <ROWDATA>
    <ROW RowState="4" ID="1" Name="one"/>
  </ROWDATA>
</DATAPACKET>

然后,您可以使用MSXML或您喜欢的XML处理器进行微不足道的更改,以便为定义FIELD数据包的METADATA添加其他CCDS个节点,添加额外的字段。然后,您从XML重新加载CDS。添加的字段值当然是NULL,并且要使此技术起作用,在从保存的XML重新加载CDS时,不得在CDS上定义持久性TField。

示例代码:

procedure TForm1.CopyWithAddedFields;
var
  SS : TStringStream;
  XMLDoc : IXmlDomDocument;
  FieldsNode : IXmlDomNode;
  FieldElement : IXmlDomElement;
begin
  SS := TStringStream.Create('');
  try
    //  Save the CDS's current contents in XML format, close it and clear any presistent fields
    CDS1.SaveToStream(SS, dfXML);
    CDS1.Close;
    CDS1.Fields.Clear;

    //  Next create an XML Document object and load the saved dataset into it
    XMLDoc := CoDomDocument.Create;
    XMLDoc.LoadXML(SS.DataString);

    //  Find the FIELDS node and add a new FIELD node to it       
    FieldsNode := XMLDoc.selectSingleNode('/DATAPACKET/METADATA/FIELDS');
    FieldElement := XMLDoc.createElement('FIELD');
    FieldElement.SetAttribute('attrname', 'Active');
    FieldElement.SetAttribute('fieldtype', 'boolean');
    FieldsNode.appendChild(FieldElement);

    // Save the XML to the stream
    SS.Size := 0;
    SS.WriteString(XmlDoc.xml);
    SS.Position := 0;

    //  Reload the ClientDataset
    CDS1.LoadFromStream(SS);
  finally
    XMLDoc.Free;
    SS.Free;
  end;
end;

显然,如果您愿意,可以将修改后的XML加载到不同的CD中。

当然,如果你准备好自己做一定数量的字符串,你甚至可以将额外的FIELD节点加载到一个TStringList中。

Fwiw,我在尝试修改CDS的XML时偶然发现了这个问题,以便在XML文件中包含每个ROW节点的额外信息;事实证明LoadFromFile&amp; LoadFromStream个进程完全忘记了我添加的信息。

答案 1 :(得分:-1)

嗯,计算字段有什么问题?你能解释一下为什么你不想使用它们吗?

一个额外提示:您是否尝试过InternalCalc(FieldKind = fkInternalCalc)。 AFAIK它的行为应该类似于数据字段(它的值存储在数据集记录中)

PS,添加计算字段时无需重新加载数据(关闭并重新打开数据集)