I’ve never really thought about this, but I’ve just noticed than when I call ApplyUpdate for (at least) two not connected datasets and one of them fails (because of concurrent edit), only the “problematic” table will be rollbacked, the other one gets silently commited (although the businessprocessor is configured to raise an exception).
How can I achieve, that one call to ApplyUpdate is processed within a single transaction?
I just tried to get the point, where the exception should raise within the BP, so that TDataAbstractService.InternalUpdateData calls DoRollbackTransaction… and that never happens.
Normally, I would expect that an exception happens, when a Create/Insert/Update-Statement fails, but in fact, this does not happen in TDABusinessProcessor.ProcessDelta. It is just handled and the “canremove”-flag is set to false. This leads to the situation, that TDADataAbstractService.InternalUpdate executes the “normal” path and calls commit (which in fact, submits all other changes, except the one, that failed) and never a rollback is applied.
I think the main issue here is, that not the command raises an exception (so the except-block within ProcessDelta is never reached), but the command itself is valid but does not update any data. This does not lead to an exeception in currcmd.Execute…
can you check that exception is raised on server-side in TDABusinessProcessor.ProcessDelta during processing “problematic” table and this exception is handled by TDABusinessProcessor.DoProcessErrorEvent?
by default, it should raise EDAApplyUpdateFailed in this method at
else if FRaiseExceptionAtError then begin
raise EDAApplyUpdateFailed.Create(aChange, Error); //<<<<<
end;
…however, this method gets called only in the except-path within ProcessDelta… but this path will not be used: an update with affectedrows=0 will just set the internal flag “canremove” to false. Neither the server nor some program code will raise any exception… and so there won’t be any call to DoProcessErrorEvent.
Maybe as a side-note: I’m currently using 9.5.0.1371
We handle errors that were raised by Direct Access Components, like PK violation, etc , i.e. errors raised on DB side.
you can handle case when change has csFailed status and raise a custom exception so it will be caught by RaiseExceptionOnError.
Although I still think, that the whole transaction should be rolled back when an Insert/Update/Delete fails (if RaiseExceptionOnError=true), the solution with the CustomEvent is still suitable.