Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Processing a ClientDataset's Delta

I've been having a problem with some code which is supposed to process a TClientDataSet's Delta, which I've boiled down to the following test case.

I have two ClientDataSets, cdsData and cdsDelta, both with a DataSource, DBGrid and DBNavigator, and a TTreeView for displaying the Delta's Old- and NewValues.

In cdsDatas AfterPost, I call the DisplayDelta procedure below.

When I run the app, I change and save the value of one field in csdData from, say, 'PrevValue' to 'UpdatedValue'. My problem is that both the OldValue and NewValue nodes in the Treeview display 'UpdatedValue' and there is no sign of 'PrevValue'. So, how do I get the OldValue correctly?

procedure TDeltaTestForm.DisplayDelta;
var
  Delta : OleVariant;
begin
  Delta := cdsData.Delta;
  if not VarIsClear(Delta) then begin
    cdsDelta.Data := Delta;
  end;
  if cdsData.Modified then
    Caption := 'modified'
  else
    Caption := '';
  Caption := Caption + '/' + IntToStr(cdsData.ChangeCount);
  BuildDeltaTree;
end;

procedure TDeltaTestForm.BuildDeltaTree;
var
  NewNode,
  ChildNode : TTreeNode;
  i,
  ID : Integer;
  Field : TField;
  Value : String;

  function ChildValue(ALabel : String; FieldValue : Variant) : String;
  begin
    Result := ALabel;
    if VarIsClear(FieldValue) then
      Result := Result + '(empty)'
    else
      if VarIsNull(FieldValue) then
        Result := Result + '(null)'
      else
        Result := Result + VarToStr(FieldValue);
  end;
begin
  { Find the current row in the delta dataset }

  ID := cdsData.FieldByName('ID').AsInteger;
  if not cdsDelta.Locate('ID', ID, []) then
    raise Exception.CreateFmt('ID: %d not found in Delta', [ID]);

  TreeView1.Items.BeginUpdate;
  try
    Treeview1.Items.Clear;
    for i:= 0 to cdsDelta.FieldCount - 1 do begin
      Field := cdsDelta.Fields[i];
      NewNode := TreeView1.Items.AddChild(Nil, Field.FieldName);
      ChildNode := TreeView1.Items.AddChild(NewNode, ChildValue('Old: ', Field.OldValue));
      ChildNode := TreeView1.Items.AddChild(NewNode, ChildValue('New: ', Field.NewValue));
      ChildNode := TreeView1.Items.AddChild(NewNode, ChildValue('Cur: ', Field.CurValue));
    end;
    TreeView1.FullExpand;
  finally
    TreeView1.Items.EndUpdate;
  end;
end;
like image 499
Alex James Avatar asked Aug 26 '16 14:08

Alex James


1 Answers

I can reproduce your problem. Try this:

Change

for i:= 0 to cdsDelta.FieldCount - 1 do begin
  Field := cdsDelta.Fields[i];

to

for i:= 0 to cdsData.FieldCount - 1 do begin
  Field := cdsData.Fields[i];

You should now find that you get the values for OldValue and NewValue you're expecting. At any rate, I do here.

I confess I'm somewhat puzzled by this - I'd always assumed that you could assign the Delta of one CDS to another and the second one would contain the same field values (Old and New) as the Delta, but evidently not. However, this result chimes with a section of Cary Jensen's excellent "ClientDataSets" ("StatusFilter Versus Delta" in Chapter 6) where he says:

" ... when you load a second CDS with a CDS's Delta, the second CDS does not have a change cache."

Maybe what he means is that what you end up with in the second one is a snapshot of the Delta, not the history of it. I guess that's why your cdsDelta returns the same values in Field.OldValue and Field.NewValue.

like image 153
MartynA Avatar answered Oct 17 '22 01:10

MartynA