我在解决如何将新数据字段添加到旧数据集文件时遇到问题。例如,旧数据集可能只有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数据集和将记录复制到新数据集。
答案 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,添加计算字段时无需重新加载数据(关闭并重新打开数据集)