3

可以在不丢失数据的情况下重组 TClientDataSet XML 文件吗?是否有任何演示应用程序或源代码显示如何进行这种重组?

4

2 回答 2

1

yes and no, the xml doc is transformed using XLST so it needs to conform to that template to be able to be read by the TClientDataSet.

However that does also mean that you can also transform the doc to any format you like yourself into a separate doc, you just can't load the transformed doc directly into the TClientDataSet.

EDIT: Oops, forgot to post an example.

This project on code central shows a transform from clientdataset to an ADO recordset.

于 2009-01-18T21:47:23.957 回答
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; 
于 2017-04-05T13:59:45.027 回答