This source code is being made available in conjunction with an article in Apple's WebObjects Context technical support bulletin for Enterprise Gold and Silver Support customers. This is the Objective C equivalent to August's WebObjects Feature Focus, on optimistic locking. Please see that article for more information. //=========== Main.h =================================== EODatabaseContext *dbContext; //an instance variable NSMutableArray *arrayOfBadEOs; //==================================================== //=========== Main.m constructor ========================= EOObjectStoreCoordinator *rootStore; EOFetchSpecification *fs; EOEditingContext *ec; ec = [[self session] defaultEditingContext]; rootStore = (EOObjectStoreCoordinator *)[ec rootObjectStore]; fs = [EOFetchSpecification fetchSpecificationWithEntityName: @"Movie" qualifier: nil sortOrderings: nil]; dbContext = (EODatabaseContext *)[rootStore objectStoreForFetchSpecification: fs]; arrayOfBadEOs = [NSMutableArray arrayWithCapacity:2]; //==================================================== //=========== Main.m action method to find bad EO's ========== NSArray *updatedEOs; NSEnumerator *enumer; id aMovie; EOGlobalID *aGlobalID; EOEditingContext *ec = [[self session] defaultEditingContext]; //[self logWithFormat: @"Main::findBadEOs called"]; updatedEOs = [ec updatedObjects]; enumer = [updatedEOs objectEnumerator]; while ( aMovie = [enumer nextObject] ) { aGlobalID = [ec globalIDForObject:aMovie]; NS_DURING [self logWithFormat: @"Main::Locking object"]; [dbContext lockObjectWithGlobalID:aGlobalID editingContext:ec ]; NS_HANDLER [self logWithFormat: @"Main:: On-demand locking failed"]; [arrayOfBadEOs addObject:aMovie]; [[self session] takeValue: badMovies forKey: @"selectedMovies"]; NS_ENDHANDLER //[self logWithFormat: @"Main:: On-demand locking succeeded"]; } [dbContext forgetAllLocks ]; return nil; //==================================================== //=========== Main.m method to refetch bad EO's ============= NSMutableArray *arrayOfBadEOs; // you got this from the code above NSMutableArray *globalIDs; NSEnumerator *enumer; id aMovie; id aGlobalID; NSArray *movies; EOFetchSpecification *fs; EOEditingContext *ec = [[self session] defaultEditingContext]; [self logWithFormat: @"Main::refeching the bad EOs"]; globalIDs = [NSMutableArray arrayWithCapacity:2]; enumer = [arrayOfBadEOs objectEnumerator]; while ( aMovie = [enumer nextObject] ) { aGlobalID = [ec globalIDForObject:aMovie]; [globalIDs addObject:aGlobalID]; } if ( [globalIDs count] > 0) [ec invalidateObjectsWithGlobalIDs:globalIDs]; fs = [EOFetchSpecification fetchSpecificationWithEntityName: @"Movie" qualifier: nil sortOrderings: nil]; movies = [ec objectsWithFetchSpecification: fs]; //==================================================== //=========================================================== private EODatabaseContext dbContext; // an instance variable EOEditingContext ec = this.session( ).defaultEditingContext( ); EOObjectStoreCoordinator rootStore = (EOObjectStoreCoordinator)ec.rootObjectStore( ); EOFetchSpecification fs = new EOFetchSpecification( "Movie", null, null); dbContext = (EODatabaseContext)((EOCooperatingObjectStore)rootStore.objectStoreForFetchSpecification( fs )); //=========================================================== When you attempt to lock an individual EO, an exception will be thrown that you can catch if the EO's snapshot is out of sync with the database. When you are done remember to release all locks. Any EOs discovered to be out of sync are splaced in array badMovies which is ultimately stored in the session object, for future reference. //=========================================================== private EODatabaseContext dbContext; // an instance variable you initialized above EOEnterpriseObject aMovie; EOGlobalID aGlobalID; NSMutableArray badMovies = new NSMutableArray( ); Session session = (Session)this.session( ); EOEditingContext ec = session.defaultEditingContext( ); NSArray updatedEOs = ec.updatedObjects( ); java.util.Enumeration enumer = updatedEOs.objectEnumerator( ); while ( enumer.hasMoreElements( ) == true ) { aMovie = (EOEnterpriseObject)enumer.nextElement( ); aGlobalID = ec.globalIDForObject( aMovie ); try { //System.out.println( "Locking EO now"]; dbContext.lockObjectWithGlobalID( aGlobalID, ec ); } catch ( Exception e ) { System.out.println( "On-demand locking failed" ); badMovies.addObject( aMovie ); } System.out.println( "On-demand locking succeeded" ); } dbContext.forgetAllLocks( ); session.takeValueForKey( new NSArray( badMovies ), "selectedMovies" ); Disclaimer ANY SOFTWARE OR SOURCE CODE INCLUDED IN THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, EXPRESS OR IMPLIED. APPLE SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL APPLE BE LIABLE FOR ANY DAMAGES, INCLUDING BUT NOT LIMITED TO ANY LOST PROFITS, LOST SAVINGS OR ANY INCIDENTAL OR CONSEQUENTIAL DAMAGES, WHETHER RESULTING FROM IMPAIRED OR LOST DATA, SOFTWARE OR COMPUTER FAILURE OR ANY OTHER CAUSE, EVEN IF APPLE IS ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY OTHER CLAIM BY CUSTOMER OR FOR ANY THIRD PARTY CLAIM.