beginTrans( ) example
The following demonstrates a simple batch transaction, transfering money from one account to another. The account table is indexed on the account number.
function transferButton_onClick
try
form.rowset.parent.database.beginTrans( )
if form.transferAmt.value <= 0
throw new AppException( "Transfer amount must be greater than zero" )
endif
do ; until form.rowset.lockSet( ) // Wait for set lock to prevent deadlock
if form.rowset.find( form.transferFrom.value )
form.rowset.fields[ "Balance" ].value -= form.transferAmt.value
else
throw new AppException( "Transfer From account not found" )
endif
if form.rowset.find( form.transferTo.value )
form.rowset.fields[ "Balance" ].value += form.transferAmt.value
else
throw new AppException( "Transfer To account not found" )
endif
form.rowset.save( )
form.rowset.parent.database.commit( )
catch ( AppException e )
form.rowset.parent.database.rollback( )
msgbox( e.message, "Tranfer failed!", 48 )
catch ( Exception e )
form.rowset.parent.database.rollback( )
logException( e )
#ifdef DEBUG
throw e
#else
fatalError( e )
#endif
endtry
As the example demonstrates, there are quite a few things that can go wrong with the transaction. These are separated into application logic errors, and all other unexpected errors. A custom class, AppException, is used for the application errors. It provides an easy way to THROW an exception with an error message.
The debit to the first row is saved when calling findKey( ) to find the second row. The credit to the second row must be saved before committing the transaction. If an application logic exception occurs, whatever is done so far (if anything) is rolled back. Then a dialog box is displayed, detailing the error. The user can try again. For all other exceptions, a function is called to log the exception for debugging purposes. Then the exception is either THROWn so that the standard error dialog appears, if the application is compiled with the debug flag on; or another function is called that details the error for the user before telling them they have to terminate the application.
logException( ) and fatalError( ) are custom functions that are left as an exercise for the developer. Here is the code for the AppException class:
class AppException( cMsg, nCode ) of Exception
if argcount( ) < 2
nCode := -1
if argcount( ) < 1
cMsg := "Application logic exception"
endif
endif
this.code := nCode
this.message := cMsg
endclass