Is it possible to re-use or re-attach the same session for the new service Iām creating or do I have to create a new session? Only reason I ask is that, if creating a new one, Iāll have to copy across properties like Roles and any Values I have on the original session.
Using the IROObjectActivation method seems to work fine so Iām going with that.
Unfortunately I then get a failure in TDataAbstractService.UnpackDeltas during the ApplyUpdates call:
DataAbstractService_Impl.TDataAbstractService.UnpackDeltas((TDADelta($7550D74) as IDADelta),$75158F0)
DataAbstractService_Impl.TDataAbstractService.InternalUpdateData((TDADelta($7550D74) as IDADelta),True)
DataAbstractService_Impl.TDataAbstractService.LDA_InternalUpdateData((TDADelta($7550D74) as IDADelta))
uDALocalDataAdapter.TDALocalDataAdapter.InternalApplyUpdates((ā¦),(ā¦))
uDADataAdapter.TDABaseDataAdapter.InternalApplyUpdatesAndThrowFailures($9B239A0,$9B22908)
uDADataAdapter.TDABaseDataAdapter.ApplyUpdates((ā¦),False)
uDADataTable.TDADataTable.InternalApplyUpdates(False)
uDADataTable.TDADataTable.ApplyUpdates(False,False)
The exact failure line in UnpackDeltas is:
If (ExportedDataTables.Count >0) then begin
ExportedDataTables is NIL. Maybe thereās something else I need to initialise?
Think Iām getting there now, thanks again for all the help.
One quick question regarding transactions - if I throw an exception in my AfterProcessChange handler, this is passed back to the client but the transaction is still committed. Surely if an exception is thrown inside any of the BP handlers then the transaction should be rolled back? Or is this controllable somehow?
Iām a little foggy on the operation of ReturnUpdateFailureDelta and RaiseExceptionAtError.
The wiki for the former refers to autogenerated BPs but Iām using my own BP components. Does this mean that ReturnUpdateFailureDelta has no effect and I should just set RaiseExceptionAtError on the BPs to True?
I have a problem when I do this. If I set RaiseExceptionAtError to True then it fixes my problem in that throwing an exception inside AfterProcessChange does cause the transaction to be rolled back (ProcessError is also called).
The problem is that, if the update itself fails to apply to the database, for example if I set a required field to NULL, then with RaiseExceptionAtError set to to true, whilst the transaction is rolled back and the error passed back to the client, ProcessError is never called. Iām using ProcessError to log such issues so I need to it be called.
I hit this issue way back when I first started with DA and got around it by setting RaiseExceptionAtError to False so ProcessError would be called, then re-raising an exception within ProcessError after Iād done my logging. If I didnāt re-raise the exception inside ProcessError then I got the built-in reconcile dialog which I didnāt want so this was the only way I could see of doing what I wanted.
Iām also not sure how ReturnUpdateFailureDelta fits into this scenario. The wiki refers to autogenerated BPs whereas Iām using my own BP components so does this option not apply?
Hmm, seems to be working correctly now with RaiseExceptionAtError set to True, even if I throw my own exception. Not sure what was going on before but seems to be working now.
Aha, I think I see whatās happening here (this is with RaiseExceptionAtError = True)
If I just thrown an exception at the end of my AfterProcessChange handler, then the transaction is rolled back and the exception passed to the client, just as I want and would expect.
If I add the code to AfterProcessChange to make the secondary changes I need, so creating a service manually and using the same connection, then this works fine with one difference - the manual exception I throw afterward doesnāt rollback the transaction.
Whatās happening is that the ApplyUpdates call on the secondary table is committing the original transaction, so if I subsequently throw an exception in my original AfterProcessChange handler, itās too late, the transaction has been committed.
This obviously isnāt going to work properly as, if my original delta had updates for several rows, then the first of these required changes in the secondary table, then the transaction would be committed by the secondary table updates, so when the second row in the original delta is processed, the transaction is no longer active.
What I need is for the secondary service to do its work within the original connectionās transaction but not commit or roll it back. If an error occurs during the secondary processing then this should be passed back up to the main processing which can then rollback the overall transaction and stop processing the rest of the main delta.
ReturnUpdateFailureDelta only inits BP.RaiseExceptionAtError for autogenerated BP. if you have some BP on form, you need to set their RaiseExceptionAtError property manually.
note: you need to set ReturnUpdateFailureDelta/RaiseExceptionAtError values for 2nd service too.
note2: RaiseExceptionAtError and ReturnUpdateFailureDelta has opposite values, i.e.
BP.RaiseExceptionAtError := not DAService.ReturnUpdateFailureDelta;