Here's the code from my framework SaveInplementation method (which is called by the template method Save that implements some hooks, etc.). Nothing special--just that it's nice to be able to "feed" an arbitrary list of open cursors to a generic object and have the transaction code wrapped for you.
This class not does not handle the view opening code or the setting of buffering: it just handles the transaction aspects.
FUNCTION SaveImplementation
LOCAL llTransOK, lnCursor
llTransOK = .T.
IF NOT THIS.lError
IF THIS.lErrorOnUnchangedSave
IF NOT THIS.PendingChanges()
ERROR "No changes were made!"
ENDIF
ENDIF
BEGIN TRANSACTION
FOR lnCursor = 1 TO THIS.nCursors
SELECT ( THIS.aCursors[ m.lnCursor] )
llTransOK = TABLEUPDATE(1)
IF NOT m.llTransOK AND NOT THIS.lError
ROLLBACK
IF NOT THIS.lError
THIS.nFailures = AERROR( THIS.aFailures)
ENDIF
IF THIS.lAutoRevert
= RevertTables()
ENDIF
EXIT
ENDIF
ENDFOR
IF m.llTransOK AND NOT THIS.lError
END TRANSACTION
ENDIF
ENDIF
RETURN m.llTransOK AND NOT THIS.lError
ENDFUNC
-- Randy
>Thanks for the tip, Randy. A generic class would definitely be more useful. Now, what method do you use in your Save()? Something other that those already proposed?
>
>>What I've done for these situations is to create a transaction class to encapsulate this behavior. It contains an AddCursor method that maintains an array of view aliases that participate in the transaction. The Save method loops through attempting TableUpdate's and either commits (END TRANSACTION) or issues ROLLBACK and optional TABLEREVERT's. The Save method returns .T. or .F. depending on success.
>>