Finally, let's talk about a form with Edit, Save and Undo Buttons. And how to combine them with Table buffering and transactions:
1. Edit:
When you start edit you don't start a transaction, the first thing most developers do here is nothing, but indeed you should now refresh all cursors with the latest data and have a clean,empty buffer, no changes yet. You do so by either just starting the buffering here, or by reverting all eventual changes with TABLEREVERT() and REQUERY() views or cursoradapters and REFRESH the form. This is often the first surprise, normally you assume nothing to do here at this stage, but data might have already changed since the form loaded. SET REFRESH also keeps the form with latest data, but only in BROWSE windows, so don't rely on that mechanism.
As I said you can start buffering here, but in the general case you can keep a form open after save or undo and start another edit session and then the tables can already be in buffering mode, so I'd start buffering with opening of tables or loading data into cursors already, then the first edit mode doesn't differ from later ones and you can do the TABLEREVERT just for any eventualities of any programmatic changes. If you already are sure those programmatic changes need to exist you can keep this or even TABELUPDATE() and store them, eg save primary keys of new records needed for this edit session. So either your edit session does already start with data changed from their original state or you have that saved and start a new session right here.
2. Save:
Here you start a VFP and remote transaction, maybe nested, but that depends on your business need. If you want to save all changes you made in the edit mode or no changes at all, one overall transaction is enough. If you update multiple tables still all referential integrity checks are made right away, neither the DBC nor a remote backend wait for integrity checks til the end of the transaction, to say it clear, you have to store data hierarchical, parent records first, then child ones to have the right and existing foreign keys, though all this is still in the transaction buffer.
If all table updates succeed the whole save was a success and you can commit the remote and local transaction, if not, it depends on your business rules what exactly to do, reverting all changes is obviously a bad move, if a user worked for an hour on the data. In the worst case the remote backend has become unavailable, you might copy workarea data into local DBFs to continue the edit session later.
3. Undo:
Here you can do what I suggested in Edit mode, too, TABLEREVERT all changes and refresh your data from the DBF or remote backend, so you see the current state of data again. The tablereverts typically are more important here, since you expect there have been changes to undo. You can always easily detect, whether a workarea has any change by GO TOP and GETNEXTMODIFIED(0), see help on that, With 0 you signal you want to find the first overall modified record. If there is none, you get 0 as return value, if you get <>0 this is the record number of the modified record. The help also states, why you have to GO TOP first. So besides setting a logical variable with any interactive change event of any field you can detect whether the undo button needs to be enabled by checking this. The edit button can switch from enabled to disabled when it's used, so that state also shows you're in an edit session or just in read mode. Besides this enabling logic you see Undo and Edit might even share the same code, or call a general "RefreshCurrentData" routine.
Especially if your form also involves navigation via navbar buttons or a list of head records you choose and move to, you can have repeated edit modes. You might want to prevent navigation within an edit session or you allow changes of several parent and child data in the same edit session. Everything is possible, if all workareas are in table buffering mode you keep all changes local and decide to save transactional when the user wants to.
Last not leas I already mentioned lengthy edit sessions. You can judge, whether that's probable or not from the complexity of the form. If things are complicated enough you can use the strategy to stor workarea data in local DBFs to have an auto save every 15 Minutes or so, like Word has, and in case of a crash or remote backend failure can offer to restart from that auto save state.
In very short:
0. open all tables/read all remote data into workareas with table buffering
1. start Edit mode: revert (or tableupdate any buffered changes. Then refresh data to most current DBF/backend state, disable this button.
1.1. While in edit mode maybe save in local DBFS for failover (autosave)
2. Save: start transaction, save and commit or revert, maybe save to local DBFs as failover, enable edit button.
3. Undo: revert changes, enable edit button. As you don't start a transaction here, you don't rollback here.
The important thing is, you only start a transaction when saving, so a rollback also only is done there and is for the case the save failed. The Undo only reverts, and revert merely reverts the buffered changes, nothing of that has been seen by the database or any other client.
Bye, Olaf.