是否可以在不丢失数据的情况下重构TClientDataSet XML文件?有没有演示应用程序或源代码来展示如何进行这样的重构?
发布于 2009-01-18 21:47:24
是也不是,xml文档是使用XLST进行转换的,因此它需要符合该模板才能被TClientDataSet读取。
然而,这也意味着您也可以将文档转换为您自己喜欢的任何格式到单独的文档中,您只是不能将转换后的文档直接加载到TClientDataSet中。
编辑:哦,忘了贴一个例子了。
代码中心上的This project显示了从客户端数据集到ADO记录集的转换。
发布于 2017-04-05 21:59:45
为了更改磁盘上的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; https://stackoverflow.com/questions/455815
复制相似问题