重组TClientdataset

时间:2009-01-18 20:15:54

标签: delphi tclientdataset

可以重构TClientDataSet XML文件而不会丢失数据吗?是否有任何演示应用程序或源代码显示如何进行此类重组?

2 个答案:

答案 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;