Реструктуризация TClientdataset - PullRequest
3 голосов
/ 18 января 2009

Можно ли реструктурировать XML-файл TClientDataSet без потери данных? Существуют ли демонстрационные приложения или исходный код, показывающий, как выполнить такую ​​реструктуризацию?

Ответы [ 2 ]

1 голос
/ 19 января 2009

да и нет, документ xml преобразуется с использованием XLST, поэтому он должен соответствовать этому шаблону, чтобы его можно было прочитать TClientDataSet.

Однако это также означает, что вы также можете преобразовать документ в любой понравившийся вам формат в отдельный документ, вы просто не можете загрузить преобразованный документ непосредственно в TClientDataSet.

EDIT: Ой, забыл опубликовать пример.

Этот проект в центральном коде показывает преобразование из набора данных клиента в набор записей ADO.

0 голосов
/ 05 апреля 2017

Чтобы внести изменения в структуру 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; 
...