views:

1422

answers:

3

In the AfterPost event handler for a ClientDataSet, I need the information if the ApplyUpdates function for the current record will do an update or an insert.

The AfterPost event will be executed for new and updated records, and I do not want to declare a new Flag variable to indicate if a 'update' or ' insert' operation is in progress.

Example code:

procedure TdmMain.QryTestAfterPost(DataSet: TDataSet);
begin
  if IsInserting(QryTest) then
     // ShowMessage('Inserting')...
  else
     // ShowMessage('Updating');

  QryTest.ApplyUpdates(-1); 
end;

The application will write a log in the AfterPost method, after ApplyUpdate has completed. So this method is the place which is closest to the action, I would prefer a solution which completely can be inserted in this event handler.

How could I implement the IsInserting function, using information in the ClientDataSet instance QryTest?

Edit: I will try ClientDataSet.UpdateStatus which is explained here.

+2  A: 

ApplyUpdates doesn't give you that information - since it can be Inserting, updating and deleting.

ApplyUpdates apply the change information stored on Delta array. That change information can, for example, contain any number of changes of different types (insertions, deletions and updatings) and all these will be applied on the same call.

On TDatasetProvider you have the BeforeUpdateRecord event (or something like that, sleep does funny things on memory :-) ). That event is called before each record of Delta is applied to the underlying database/dataset and therefore the place to get such information... But Showmessage will stop the apply process.

EDIT: Now I remembered there's another option: you can assign Delta to another clientdataset Data property and read the dataset UpdateStatus for that record. Of course, you need to do this before doing applyupdates...

var
  cdsAux: TClientDataset;
begin
  .
  . 
  <creation of cdsAux>
  cdsAUx.Data := cdsUpdated.Delta;
  cdsAux.First;
  case cdsAux.UpdateStatus of
    usModified:
      ShowMessage('Modified');
    usInserted:
      ShowMessage('Inserted');
    usDeleted:
      ShowMessage('Deleted'); // For this to work you have to modify  
                              // TClientDataset.StatusFilter  
  end;
  <cleanup code>
end;
Fabricio Araujo
This sounds very good. If the ApplyUpdate is only related to one record, the Delta arry will only contain one entry which knows if it is an update or insert? So I need only a way to access this information in the Delta.
mjustin
Why does it use a second CDS? I would expect that the UpdateStatus is already available in the first CDS, so I could just read it directly. Or is StatusFilter the answer why a second one is needed?
mjustin
Because with the 2nd cds you'll have just content of the Delta, and nothing more. But it's just an alternative way to do the thing, without going through the dataset provider.
Fabricio Araujo
This is the solution I was dreaming of - with the only addition that the dataset needs to be filtered as explained in Cary Jensens answer, to avoid the unmodified delta records. I am using this now in a demo for database change notifications over a message broker (Apache ActiveMQ or OpenMQ).
mjustin
+4  A: 

BeforeUpdateRecord event on TDataSetProvider is defined as:

procedure BeforeUpdateRecord(Sender: TObject;  SourceDS: TDataSet; DeltaDS:
                             TCustomClientDataSet; UpdateKind: TUpdateKind;
                             var Applied: Boolean);

Parameter UpdateKind says what will be done with record: ukModify, ukInsert or ukDelete. You can test it like this:

procedure TSomeRDM.SomeProviderBeforeUpdateRecord(Sender: TObject;
      SourceDS: TDataSet; DeltaDS: TCustomClientDataSet; UpdateKind: TUpdateKind;
      var Applied: Boolean);
begin
  case UpdateKind of
    ukInsert :
         // Process Insert;
    ukModify :
         // Process update
    ukDelete :
         // Process Delete
  end;
end;

Note: this event signature is from Delphi 7. I don't know if it changed in later versions of Delphi.

zendar
+2  A: 

Set the ClientDataSet.StatusFilter to an TUpdateStatus value, and then read ClientDataSet.RecordCount

for example,

 ClientDataSet1.StatusFilter := [usDeleted];
 ShowMessage(IntToStr(ClientDataSet1.RecordCount));

will return the number of Delete queries that will be executed.

Note two things, however. Setting StatusFilter to usModified always includes both the modified and unmodified records, so you take half of that value (a value of 4 means 2 Update queries will be executed). Also, setting StatusFilter to [] (an empty set) is how you restore to default view (Modified, Unmodified, and Inserted)

Make sure that any unposted changes have been posted before doing this, otherwise unposted changes may not be considered.

Cary Jensen
Many thanks, this was the missing piece of the easiest solution! See my comment in the answer from Fabricio Araujo.
mjustin