Question
Joseph Tsang · Jul 14

About the callback method %OnSaveFinally()

Is there anyone using this callback in the code? I was searching in the latest IRIS documentation for any handy callbacks of the %Persistent class which allows me to execute some codes just right after a transaction has been committed (TCOMMIT). The description of this %OnSaveFinally() sounds the thing I want because it said:

If the calling method started a transaction then that transaction is completed prior to invoking the callback.

However, I later discovered in my own test that this callback is triggered after %Save(), not after TCOMMIT.

 

Product version: IRIS 2022.1
0
0 246
Discussion (5)3
Log in or sign up to continue

Hello, as the documentation is saying, the call to %OnSaveFinally() is done at the last step of the %Save() = after data was written to the database, and the transaction is already committed.

I did a test with a class:

Class USER.TestClass Extends %Persistent
{
   Property Name As %String;
   ClassMethod %OnSaveFinally(oref As %ObjectHandle, status As %Status)
   {
      S ^TestGlobal="This is a test "_$ZDT($H)
   }
}

Then, I've saved some new data into the class:

USER>s obj=##class(USER.TestClass).%New(), obj.Name="Name", sc=obj.%Save() w !,sc
1
USER>zw ^USER.TestClassD
^USER.TestClassD=1
^USER.TestClassD(1)=$lb("","Name")

and then checked the journal entries to see the behavior.
It shows that the %OnSaveFinally() was called just after a successful save after the CT (close of transaction):

1675920  2312 BT  1675936 2312 S  +\iris\mgr\user\ USER.TestClassD = 1
1675992  2312 ST +\iris\mgr\user\ USER.TestClassD(1) = $lb("","Name")       
1676052  2312 CT
1676068  2312 S  +\iris\mgr\user\ TestGlobal = "This is a test 07/15/202+

Hi Yaron, thanks for giving a test with the code example above. And the statement you referred is indeed from the documentation.

Yet to me the "transaction" mentioned is a bit ambiguous. I would rather interpret it as an explicit transaction demarcated by a TSTART and a TCOMMIT (or TROLLBACK) in the calling method.

Let me continue with your example here. This time I would like to add TSTART and TCOMMIT for the scope of the transaction, and there in the transaction I would like to add and save the second object:

USER>TSTART
USER>s obj=##class(USER.TestClass).%New(), obj.Name="Name", sc=obj.%Save() w !,sc
1
USER>zw ^USER.TestClassD
^USER.TestClassD=1
^USER.TestClassD(1)=$lb("","Name")
USER>s obj=##class(USER.TestClass).%New(), obj.Name="Name2", sc=obj.%Save() w !,sc
1
USER>zw ^USER.TestClassD
^USER.TestClassD=2
^USER.TestClassD(1)=$lb("","Name")
^USER.TestClassD(2)=$lb("","Name2")
USER>TCOMMIT

And what I really expect to see is, the %OnSaveFinally() method of those 2 objects will be called at the point just after TCOMMIT in my example, not after their own %Save() respectively.

I submitted some feedback to documentation regarding the content you cited.

The line in question originated from something I wrote while implementing the %On*Finally set of methods. The "calling method" in this context refers to the method that invokes the %On*Finally() method. In this case, %Save() is the calling method.

%Save may or may not initiate a transaction, depending on a few factors. If %Save does initiate a transaction then that transaction is complete prior to the %OnSaveFinally() call.

So this thread has clarified that the transaction that you read about in the docs is the transaction inside %Save(), and %OnSaveFinally() is a callback for %Save(). Your original question seems to be asking if the TCOMMIT command itself triggers a callback, but it doesn't. You could of course add your own code right after the TCOMMIT, but I guess that's not what you're looking for with this question.

Thanks for your inputs, Dan, Joel. And you're right. Perhaps I was trying to look up a callback somewhat like %OnAfterCommit() instead.