可以重构TClientDataSet XML文件而不会丢失数据吗?是否有任何演示应用程序或源代码显示如何进行此类重组?
答案 0 :(得分:1)
是和否,xml doc使用XLST进行转换,因此需要符合该模板才能被TClientDataSet读取。
但是,这也意味着您还可以将文档转换为您喜欢的任何格式到单独的文档中,您只是无法将转换后的文档直接加载到TClientDataSet中。
编辑: 哎呀,忘了张贴一个例子。
代码中心的This project显示从clientdataset到ADO记录集的转换。
答案 1 :(得分:0)
为了更改磁盘上的CDS结构,我使用了下面列出的子类。我们将数据以二进制格式写入流中(在压缩/加密之前),但它对于XML格式应该大致相同。
如果您需要添加/删除已保存数据集中的任何字段或更改字段定义,则只需增加数据集表格版本。每次打开数据集时,它会将保存的版本号与当前值进行比较。如果保存的表是旧的,它将被复制到新结构中,因此如果您需要进行更改,您将在第一次重新加载表时执行一次性能命中,但之后应该像往常一样从磁盘加载。
因此,如果您在完成合并后将CDS保存回磁盘 - 瞧 - 您的XML结构将以CDS友好格式更新。
TCDS = class(TCustomClientDataset)
private
fTableVersion: integer;
/// <summary> Copies records from source with potentially different table
/// structure/field defs from self, providing defaults for missing fields</summary>
procedure CopyFromDataset(const ASource: TCustomClientDataset);
/// <summary>Provide a default value, if necessary, for any new fields</summary>
function GetDefaultValue(const AFieldName: string): variant;
public
procedure LoadFromStream(AStream: TStream);
procedure SaveToStream(AStream: TStream);
end;
procedure TCDS.LoadFromStream(AStream: TStream);
var
ATemp: TCDS;
APersistedVersion: integer;
begin
AStream.ReadData(APersistedVersion);
if APersistedVersion = fTableVersion then
begin
Close;
ReadDataPacket(AStream, True);
Open;
end
else if APersistedVersion < fTableVersion then
begin
// It's an old table structure:
// - Load old structure into temp CDS
// - Merge temp CDS records into new structure
ATemp := TCDS.Create;
try
ATemp.Close;
ATemp.ReadDataPacket(AStream, True);
ATemp.Open;
CopyFromDataset(ATemp);
finally
FreeAndNil(ATemp);
end;
end;
end;
procedure TCDS.SaveToStream(AStream: TStream);
begin
AStream.WriteData(fVersionNumber);
WriteDataPacket(AStream, True);
end;
procedure TCDS.CopyFromDataset(const ASource: TCustomClientDataset);
var
ACurrentFieldNames: TStrings;
i: integer;
begin
// Assuming we don't want to keep any records already in dataset
EmptyDataSet;
ACurrentFieldNames := TStringList.Create;
try
Fields.GetFieldNames(ACurrentFieldNames);
for i := 0 to ACurrentFieldNames.Count-1 do
ACurrentFieldNames.Objects[i] := ASource.Fields.FindField(ACurrentFieldNames[i]);
ASource.First;
while not ASource.Eof do
begin
Append;
for i := 0 to Fields.Count-1 do
begin
if Assigned(ACurrentFieldNames.Objects[i]) then
Fields[i].Value := TField(ACurrentFieldNames.Objects[i]).Value
else if Fields[i].Required then
Fields[i].Value := GetDefaultValue(ACurrentFieldNames[i]);
end;
Post;
ASource.Next;
end;
finally
FreeAndNil(ACurrentFieldNames);
end;
end;