2.5 Managing Transactions Manually
As we have seen, when a transaction is active (following a beginTransaction), ReStore will track changes to persistent objects and add those objects to the active transaction. All changes are then committed (or rolled-back) in a single step.
This automatic tracking of changes has many advantages: no special actions are required to mark an object has changed, and so your application does not need to consider which objects it is likely to change. Thus fully persistent applications are quick and easy to construct.
In some circumstances you may want to take more control of the updating of your persistent objects. One scenario where this is possible is if you prefer to structure your application as a number of mode-less screens. By mode-less, we mean that the user is free to switch between different screens at will, as opposed to modal screens, which restrict the user to working on one screen at once.
If each mode-less screen has its own 'Apply Changes' button, then the single transaction model is not appropriate - sending commitTransaction to ReStore would commit all changes made, regardless of from which screen they originated. What is required is for each screen to manually notify ReStore of which objects it has changed (or is likely to have changed).
In order to do this, ReStore provides the message commitObjects:. The argument to this message is a collection of the potentially-changed objects. When commitObjects: is sent to ReStore, a transaction is begun, the collection of objects is added to the transaction, and then the transaction is committed - all in a single step.
The important point to grasp is that it is perfectly valid for persistent objects to be modified outside of a transaction. It is only necessary to add a changed object to a transaction in order to commit (or rollback) those changes.
As with commitTransaction, commitObjects: returns a Boolean indicating whether the changes were successfully written to the database. If the updates fail, a transaction is left open - you must manually instruct ReStore how to handle it (rollbackTransaction, rollbackAndRefreshTransaction etc.) as normal.
Storing and Unstoring objects
During a normal 'open' transaction, objects can be made persistent via the storeIn: message, and unstored with the unstore message.
In order to store new objects and unstore existing objects as part of a commitObjects: message, it is necessary to qualify the relevant objects via a descriptive message. In the following examples, the objects are updated, stored, and unstored respectively:
"Using a standard transaction"
newObject storeIn: aReStore.
"Equivalent using commitObjects:"
self reStore commitObjects:
add: newObject stored;
add: oldObject unstored;
In the same way as commitObjects: will commit changes made to persistent objects, rollbackObjects: will rollback changes to those objects, effectively undoing any changes made to them.
In a similar way to rollbackObjects:, refreshObjects: also undoes changes made to the collection of objects passed as its parameter.
The difference between the two is that rollbackObjects: undoes changes by rolling-back to the original state of the objects as held by ReStore (ReStore caches an original copy of each object in order to detect the changes made). refreshObjects: on the other hand actually discards the in-memory versions of the objects - thus next time they are referenced, the objects' data is re-read from the database.
refreshObjects: is useful where you anticipate changes have been made in the database by other users. It can be used at any time, providing there is no active transaction.
refreshAllObjects operates in the same way as refreshObjects:, but operates on all persistent objects known to ReStore. It is an easy way to force a refresh of all in-memory objects.