Delphi 重新构造TClientdataset

Delphi 重新构造TClientdataset,delphi,tclientdataset,Delphi,Tclientdataset,TClientDataSet XML文件是否可以在不丢失数据的情况下重新构造?是否有演示应用程序或源代码显示如何进行这种重构?是和否,xml文档使用XLST进行转换,因此它需要符合该模板才能被TClientDataSet读取 然而,这也意味着您可以将文档转换为您喜欢的任何格式,并将其转换为单独的文档,您只是不能将转换后的文档直接加载到TClientDataSet中 编辑: 哎呀,忘了发一个例子了 在代码中心显示了从clientdataset到ADO记录集的转换。为了更改磁盘上的CDS结构,我使用

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

是和否,xml文档使用XLST进行转换,因此它需要符合该模板才能被TClientDataSet读取

然而,这也意味着您可以将文档转换为您喜欢的任何格式,并将其转换为单独的文档,您只是不能将转换后的文档直接加载到TClientDataSet中

编辑: 哎呀,忘了发一个例子了


在代码中心显示了从clientdataset到ADO记录集的转换。

为了更改磁盘上的CDS结构,我使用了下面概述的子类。我们以二进制格式将数据写入流(在压缩/加密之前),但对于XML格式,其工作原理应该大致相同

如果需要从保存的数据集中添加/删除任何字段或更改字段定义,则只需增加数据集表的版本。每次打开数据集时,它都会将保存的版本号与当前版本号进行比较。如果保存的表是旧的,它将被复制到新的结构中,因此如果您需要进行更改,第一次重新加载表时将受到一次性能影响,但之后应像往常一样从磁盘加载

因此,如果在执行合并操作后将CD保存回磁盘,那么XML结构将以CD友好的格式更新

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; 
TCDS=class(TCustomClientDataset)
私有的
fTableVersion:整数;
///从具有潜在不同表的源复制记录
///结构/字段从self定义,为缺少的字段提供默认值
过程CopyFromDataset(const ASource:TCustomClientDataset);
///如有必要,为任何新字段提供默认值
函数GetDefaultValue(const AFieldName:string):变量;
公众的
程序加载源流(AStream:TStream);
程序保存到流(AStream:TStream);
结束;
程序TCDS.LoadFromStream(AStream:TStream);
变量
ATemp:中药;
APersistedVersion:整数;
开始
AStream.ReadData(辅助版本);
如果APersistedVersion=fTableVersion,则
开始
接近;
ReadDataPacket(AStream,True);
打开
结束
否则,如果辅助版本<故障诊断版本,则
开始
//这是一个旧的表结构:
//-将旧结构加载到临时CD中
//-将临时CD记录合并到新结构中
ATemp:=TCDS.Create;
尝试
ATemp.关闭;
ATemp.ReadDataPacket(AStream,True);
ATemp.打开;
CopyFromDataset(ATemp);
最后
自由零(ATemp);
结束;
结束;
结束;
程序TCDS.SaveToStream(AStream:TStream);
开始
AStream.WriteData(fVersionNumber);
WriteDataPacket(AStream,True);
结束;
过程TCDS.CopyFromDataset(const ASource:TCustomClientDataset);
变量
acurrenfieldnames:TStrings;
i:整数;
开始
//假设我们不想在数据集中保留任何记录
空数据集;
acurrenfieldnames:=TStringList.Create;
尝试
字段。GetFieldName(acurrenfieldnames);
对于i:=0到acurrenfieldnames.Count-1 do
acurrenfieldnames.Objects[i]:=ASource.Fields.FindField(acurrenfieldnames[i]);
A来源:第一;
而不是一个资源。Eof做什么
开始
追加
对于i:=0到Fields.Count-1 do
开始
如果已分配(acurrenfieldnames.Objects[i]),则
字段[i]。值:=TField(ACurrentFieldNames.Objects[i])。值
否则,如果字段[i]为必填项,则
字段[i]。值:=GetDefaultValue(ACurrentFieldNames[i]);
结束;
邮递
A来源。下一步;
结束;
最后
FreeAndNil(acurrenfieldnames);
结束;
结束;