PATH  WebObjects 4.0 Documentation > EOF Developer's Guide

Table of Contents Previous Section

Saving Changes

In a running application, the changes users make to objects are reflected in the object graph managed by an EOEditingContext and in the user interface. However, the database isn't updated to reflect these changes until there is an explicit request (typically issued by the user) to save. The sequence of events in a save operation is illustrated in Figure 52.

Figure 52. Saving to the Database

When an EOEditingContext receives a request to save in the form of a saveChanges message, the following sequence of events occurs:

  1. The editing context sends it editors and delegates the message editingContextWillSaveChanges.

  2. The editing context processes, propagates, and validates deletes.

  3. The editing context processes and validates changes for saving.

  4. The editing context commits the changes made to its objects to its parent object store by sending the parent the message saveChangesInEditingContext (saveChangesInEditingContext: in Objective-C). If the editing context is not nested, its parent is typically an EOObjectStoreCoordinator. When an EOObjectStoreCoordinator receives this message, it guides its EOCooperatingObjectStores through a multi-pass save protocol in which each cooperating store saves its own changes and forwards remaining changes to other cooperating stores.

  5. After it receives the message saveChangesInEditingContext, the object store coordinator sends each of its cooperating stores a prepareForSaveWithCoordinator message (prepareForSaveWithCoordinator:editingContext: in Objective-C), which informs them that a multi-pass save operation is beginning. When the cooperating store is an EODatabaseContext, it takes this opportunity to generate primary keys for any new objects in the editing context.

  6. The coordinator sends each of its cooperating stores the message recordChangesInEditingContext, which prompts them to examine the changed objects in the editing context, record any operations that need to be performed, and notify the coordinator of any changes that need to be forwarded to other cooperating stores. For example, if in its recordChangesInEditingContext method one cooperating store notices the removal of an object from an "owning" relationship but that object belongs to another cooperating store, it informs the other store by sending the coordinator a forwardUpdateForObject message (forwardUpdateForObject:changes: in Objective-C).

  7. The coordinator sends each of its cooperating stores the message performChanges. This tells the stores to transmit their changes to their underlying databases. When the cooperating store is an EODatabaseContext, it responds to this message by taking the EODatabaseOperations that were constructed in the previous step, constructing EOAdaptorOperations from them, and giving the EOAdaptorOperations to an available EOAdaptorChannel for execution.

  8. If performChanges fails for any of the EOCooperatingObjectStores, all stores are sent the message rollbackChanges.

  9. If performChanges succeeds for all EOCooperatingObjectStores, the receiver sends them the message commitChanges, which has the effect of telling the adaptor to commit the changes.

  10. If commitChanges fails for a particular cooperating store, that store and all subsequent ones are sent the message rollbackChanges. However, the stores that have already committed their changes do not roll back. In other words, the EOObjectStoreCoordinator doesn't perform the two-phase commit protocol necessary to guarantee consistent distributed update.

  11. If the save operation was successful, the editing context updates its object snapshots.

  12. Once it has committed its changes to its parent object store, the editing context posts the EditingContextDidSaveChangesNotification (EOEditingContextDidSaveChangesNotification in Objective-C).

Customizing Framework Behavior

You can customize the behavior a save operation by assigning delegates to EOEditingContext and EOAdaptorChannel, and implementing the any of the following delegate methods.
EOEditingContext Delegate Methods
Java Method Objective-C Method Description
editingContext
ShouldValidateChanges
editingContext
ShouldValidateChanges:
This method is invoked when an EOEditingContext receives a saveChanges message. If the delegate returns false (NO), changes are saved without first performing validation. You can use this method to provide your own validation mechanism.
editingContext
WillSaveChanges
editingContext
WillSaveChanges:
This method is invoked when an EOEditingContext receives a saveChanges message. You can use this method to perform other pre-save validation.
EOAdaptorChannel Delegate Methods
Java Method Java Method Description
databaseContextWillOrder
AdaptorOperations
databaseContext:
willOrder
AdaptorOperations
FromDatabaseOperations:
This method is invoked when EODatabaseContext receives a performChanges message. You can use this method to construct your own adaptor operations, for instance, possibly transform a delete operation into an update, or a stored procedure invocation.
databaseContext
WillPerform
AdaptorOperations
databaseContext:
willPerform
AdaptorOperations:
adaptorChannel:
This method is invoked from the EODatabaseContext performChanges method. This method is useful for applications that need a special ordering of adaptor operations; for example, to avoid violating any database referential integrity constraints.

You can also register to receive the notifications listed below
EOEditingContext Notifications
Notification Description
EditingContextDidSaveChangesNotification (EOEditingContextDidSaveChangesNotification in Objective-C) This notification is broadcast after changes are saved to the editing context's parent object store.
ObjectsChangedInStoreNotification (EOObjectsChangedInStoreNotification in Objective-C) This notification is broadcast by the database context when object updates are committed to the database.

Locking and Update Strategies

An update operation includes the following ingredients:

There must also be a transaction in progress.

The "means of identifying" a row is the primary key or global ID.

An update strategy determines how updates should be made in the face of changes by others. For example, one strategy is to lock a row when it is read so that no one else can change it until you're done with it; this is called pessimistic locking. Another strategy is to compare the state of a row as you fetched it-that is, the row's snapshot-with the database row at update time to confirm that the database row hasn't been changed by someone else. This is called optimistic locking, because it assumes a conflicting update won't occur, but does check at the last minute. You can set your update strategy using the EODatabaseContext method setUpdateStrategy (setUpdateStrategy: in Objective-C). Optimistic locking is the default.

Enterprise Objects Framework also supports "on-demand" locking, in which specific optimistic locks can be promoted to database locks during the course of program execution. In other words, you can lock single objects. There are three ways to use on-demand locking. Use the EODatabaseContext method lockObjectWithGlobalID (lockObjectWithGlobalID:editingContext: in Objective-C) to lock a database row for a particular object. Use the EODatabaseContext method objectsWithFetchSpecification (objectsWithFetchSpecification:editingContext: in Objective-C) with a fetch specification that's configured to lock rows as they're fetched. Or use the EOEditingContext method lockObject (lockObject: in Objective-C).

Handling Conflicts

The locking approach you use determines at what point conflicts are detected and how you can handle them.

Table of Contents Next Section