|
2. Persistency
2.2 Transactions
Whenever you are creating or updating objects in the database, you will need to use a transaction. Transactions are a way of packaging together a batch of changes to persistent objects. During the transaction there is no actual interaction with the database, all changes are stored in memory. At the end of the transaction, you may commit the stored changes to the database, at which point they become persistent. Alternatively, changes may be rolled back, leaving the database unchanged and the objects in memory in their original state, prior to the start of the transaction.
Examples:
aReStore beginTransaction.
johnSmith := Person new.
johnSmith
surname: 'Smith';
firstName: 'John';
storeIn: aReStore.
"johnSmith does not exist in the database at this point"
aReStore commitTransaction.
"johnSmith is now persistent"___
aReStore beginTransaction.johnSmith surname: 'Smythe'.
"johnSmith's surname is now 'Smythe'.
However it is still stored in the database as 'Smith' "(MessageBox confirm: 'Save Changes?')
ifTrue:
[aReStore commitTransaction
"johnSmith is now named 'John Smythe' in the database"]
ifFalse:
[aReStore rollbackTransaction
"johnSmith's surname has reverted to 'Smith' "]
This second example shows how transactions can be useful in allowing users to make changes then select whether to save these or not. ReStore includes a new subclass of Dialog which takes advantage of this - TransactionalDialog.
Block Transactions
If you know you are going to commit a set of changes, you may find it more convenient to put those changes in a block as follows:aReStore evaluateAsTransaction: [johnSmith surname: 'Smythe']
This is equivalent to:
aReStore beginTransaction.
johnSmith surname: 'Smythe'.
aReStore commitTransactionAn advantage to using a block transaction is that if there is an error during the execution of the block, the whole transaction will be automatically rolled back, allowing you to retry from the beginning of the block.
TransactionalDialog
The ability to batch together and optionally save or abandon changes is particularly useful within the scenario of a dialog window. In a standard Dolphin image, you can subclass Dialog to obtain this behavior, which uses an AspectAdapter to provide the optional commit/rollback of changes. You can still use this mechanism with ReStore, managing the transactions yourself, however you will probably find it easier to use the ReStore class TransactionalDialog.TransactionalDialog is a subclass of the regular Dolphin Dialog class which automatically manages the begin, commit and rollback of transactions in response to the following standard command messages:
apply - commit all outstanding changes, leaving the window open
revert - rollback all outstanding changes, leaving the window open
ok - commit all outstanding changes and close the window
cancel - rollback all outstanding changes and close the window
You may take advantage of these facilities by simply subclassing TransactionalDialog with your own Dialog class. By setting an already-persistent object as the model of your Dialog, the object can be edited with full Apply/Revert/OK/Cancel functionality, or by specifying a default model in the usual way, TransactionalDialog will automatically store the new object when (if) the user hits the OK or Apply buttons.
For examples of the use of TransactionalDialog, study the Entertainment Shop classes:
CustomerMaintenanceDialog
OrderMaintenanceDialog
StockMaintenanceDialog