Hello,
I’ve currently implemented the following Event to achieve an automated Log of changed records.
(Next to this “EventHandler” I’ve also set the fields Modficiation count (MCNT), Modfication User (MUSR) and Last Modification Timestamp (LMTS) to ServerAutoRefresh)
procedure [TDataAbstractService].DataAbstractServiceBeforeProcessDeltas(aSender: TObject; aDeltaStructs: TDADeltaStructList);
var
iUserID : Integer;
utcNow : TUtcDateTime;
iStructCnt : Integer;
tDelta : TDADelta;
sTable : String;
iChangeCnt : Integer;
dcDeltaChange : TDADeltaChange;
tDataSet : TDADataSet;
sFLPX : String;
iMCNT : Integer;
dsDeltaStruct : TDADeltaStruct;
iDeltaLog : IDADelta;
bpDeltaLog : TDABusinessProcessor;
tDeltaChangeLog : TDADeltaChange;
iCnt : Integer;
begin
iUserID := Session[ Global.SESSION_USERID ];
utcNow := Global.getUTC;
for iStructCnt := aDeltaStructs.Count - 1 downto 0 do
begin
tDelta := aDeltaStructs[ iStructCnt ].Delta.GetDelta;
sTable := tDelta.LogicalName;
aDeltaStructs[ iStructCnt ].BusinessProcessor.RaiseExceptionAtError := true;
dsDeltaStruct := nil;
tDataSet := ServiceSchema.Datasets.FindDatasetByName( sTable );
{ TODO : THIS IS A NOT OPTIMAL --> TRY TO FIND THE FIELDS BY ITERATING OVER THEM AND USING LeftStr or so }
sFLPX := tDataSet.Fields[ 0 ].Name.Substring( 0, 2 );
for iChangeCnt := 0 to tDelta.Count - 1 do
begin
dcDeltaChange := tDelta.Changes[ iChangeCnt ];
if ( dcDeltaChange.ChangeType = ctInsert ) or
NOT Assigned( tDataSet.FindField( sFLPX + 'MCNT' ) ) then
iMCNT := 0
else
iMCNT := VarToIntDef( dcDeltaChange.OldValueByName[ sFLPX + 'MCNT' ], -1 ) + 1;
if NOT Assigned( dsDeltaStruct ) then
begin
iDeltaLog := NewDelta( 'ZZM_' + tDelta.LogicalName );
for iCnt := 0 to tDataSet.Fields.Count - 1 do
iDeltaLog.AddFieldName( tDataSet.Fields[ iCnt ].Name, tDataSet.Fields[ iCnt ].DataType );
iDeltaLog.AddFieldName( sFLPX + 'LVTS', datLargeInt );
for iCnt := 0 to tDelta.KeyFieldCount - 1 do
iDeltaLog.AddKeyFieldName( tDelta.KeyFieldNames[ iCnt ] );
iDeltaLog.AddKeyFieldName( sFLPX + 'LVTS' );
//for this BP we also use the Owner of the original BP
bpDeltaLog := TDABusinessProcessor.Create( aDeltaStructs[ iStructCnt ].BusinessProcessor.Owner );
bpDeltaLog.Assign( aDeltaStructs[ iStructCnt ].BusinessProcessor );
bpDeltaLog.ReferencedDataset := iDeltaLog.LogicalName;
//--> IF THIS IS SET I CAN'T RAISE AN EXCEPTION AGAIN --> THIS leads to an AV
//bpDeltaLog.OnProcessError := DABusinessProcessor1ProcessError;
dsDeltaStruct := aDeltaStructs.Add( iDeltaLog, bpDeltaLog );
end;
//Update old Entry from Log...
if dcDeltaChange.ChangeType <> ctInsert then
begin
tDeltaChangeLog := iDeltaLog.Add( iDeltaLog.Count, ctUpdate );
tDeltaChangeLog.OldValues := dcDeltaChange.OldValues;
tDeltaChangeLog.OldValueByName[ sFLPX + 'LVTS' ] := High( Int64 );
tDeltaChangeLog.NewValues := dcDeltaChange.OldValues;
tDeltaChangeLog.NewValueByName[ sFLPX + 'LVTS' ] := utcNow;
end;
//Apply Server-Changes...
if Assigned( tDataSet.FindField( sFLPX + 'MCNT' ) ) then dcDeltaChange.NewValueByName[ sFLPX + 'MCNT' ] := iMCNT;
if Assigned( tDataSet.FindField( sFLPX + 'MUSR' ) ) then dcDeltaChange.NewValueByName[ sFLPX + 'MUSR' ] := iUserID;
if Assigned( tDataSet.FindField( sFLPX + 'LMTS' ) ) then dcDeltaChange.NewValueByName[ sFLPX + 'LMTS' ] := utcNow;
//Write new Entry in Log...
if dcDeltaChange.ChangeType <> ctDelete then
begin
tDeltaChangeLog := iDeltaLog.Add( iDeltaLog.Count, ctInsert );
tDeltaChangeLog.NewValues := dcDeltaChange.NewValues;
tDeltaChangeLog.NewValueByName[ sFLPX + 'LVTS' ] := High( Int64 );
end;
end;
end;
end;
I just want to know:
- Do I have to think about possible problems regarding MultiThreading?
- What about the OnError-Handler for the BusinessProcessor:
If I assign it I cannot raise the error for the client: in this case I get a Streaming Error resulting in an AV
Best regards,
Peter