home *** CD-ROM | disk | FTP | other *** search
/ OpenStep (Enterprise) / OpenStepENTCD.toast / OEDEV / EODEV.Z / EODatabaseContext.h < prev    next >
Encoding:
Text File  |  1996-09-09  |  25.3 KB  |  484 lines

  1. // EODatabaseContext.h 
  2. // Copyright (c) 1994, NeXT Software, Inc.  All rights reserved.
  3.  
  4. #import <EOControl/EOControl.h>
  5. #import <EOAccess/EODefines.h>
  6.  
  7. @class EODatabase;
  8. @class EODatabaseChannel;
  9. @class EOAdaptorContext;
  10. @class EOAdaptorChannel;
  11. @class EOModel;
  12. @class EOEntity;
  13. @class EORelationship;
  14. @class EOAdaptorOperation;
  15. @class EODatabaseOperation;
  16.  
  17. // EODatabaseContext is the basic EOObjectStore for the access framework. It
  18. // acts as one of possibly several EOCooperatingObjectStores for an
  19. // EOObjectStoreCoordinator. It acts as a store for any entities in its
  20. // EODatabase's model list. When saving EditingContext changes, the EODatabaseContext
  21. // searches the object graph using the EditingContexts list of inserted, deleted,
  22. // and updated objects and determines exactly which changes need to be made in
  23. // the database. It then creates an array of adaptorOperations which it hands to
  24. // an adaptor channel for execution.
  25. //
  26. // The EODatabaseContext knows how to interact with other EOCooperatingObjectStores
  27. // to save changes made to an object graph in more than one database server.
  28. //
  29. // When the EODatabaseContext is asked to fetch or write information to the database
  30. // is tries to use one of its EODatabaseChannels. If all of it's channels are busy,
  31. // it broadcasts a EODatabaseChannelNeededNotification in the hopes that some observer
  32. // can provide a new channel for the context or that an existing channel can be freed
  33. // up.
  34. //
  35. // An EODatabaseContext represents a single transaction scope on the database
  36. // server, and determines the updating and locking stragegy used by the
  37. // database layer.  It's managed by an EODatabase object, which represents the
  38. // main connection to the server.  If the server supports multiple concurrent
  39. // transaction sessions, the EODatabase may have several EODatabaseContexts.
  40. // If the adaptor allows multiple channels per context, then an EODatabaseContext
  41. // may in turn have several EODatabaseChannels, which handle actual access to
  42. // the data on the server.  An EODatabaseContext by default has no
  43. // EODatabaseChannels; to create a new EODatabaseChannel, allocate and
  44. // initialize one with -initWithDatabaseContext:.  See EODatabase.h and
  45. // EODatabase Channel.h for more information.
  46. //
  47. // Not all adaptors support multiple contexts per database object.
  48. //
  49. // An EODatabaseContext creates an EOAdaptorContext when initialized, and uses
  50. // this object to actually communicate with the database server.
  51. //
  52. // UPDATING AND LOCKING STRATEGIES
  53. //
  54. // EODatabaseContext supports three updating stategies. The following sections
  55. // describe each of the update modes in detail.
  56. //
  57. // EOUpdateWithPessimisticLocking:
  58. //
  59. // Under pessimistic locking, objects are locked when they're selected.  This
  60. // ensures that no one else can modify the objects until your transaction ends.
  61. // However, this doesn't necessarily mean that YOUR update will succeed.
  62. // Other settings at the adaptor or physical database level can cause your
  63. // update to fail.  When pessimistic locking is enabled, a transaction is automatically
  64. // started on the upon the first access to the database.  By default, all selects
  65. // against the database are performed with "select FOR UPDATE".  The transaction is
  66. // ended either when saveChangesInEditingContext: is invoked and the transaction is
  67. // committed, or when revertAllObjects is called and the transaction is rolled back.
  68. // By default, when the transaction is closed, all snapshot are invalidated and all
  69. // objects based on those snapshots are invalidated (refaulted).
  70. //
  71. // EOUpdateWithOptimisticLocking:
  72. //
  73. // Under optimistic locking, objects aren't locked on the server: When you
  74. // attempt to update an object in the database, the object's snapshot is used
  75. // to ensure that the values in the corresponding database row have not
  76. // changed since the object was fetched.  As long as the snapshot matches the
  77. // database, the update is allowed to proceed.  EOUpdateWithOptimisticLocking
  78. // is the default update strategy.
  79. //
  80. // EOUpdateWithNoLocking:
  81. //
  82. // Under the no-locking strategy, objects are never locked.  No comparisons
  83. // are made between the snapshot and the row to ensure that the values in the
  84. //
  85.  
  86. typedef enum {
  87.     EOUpdateWithOptimisticLocking,
  88.     EOUpdateWithPessimisticLocking,
  89.     EOUpdateWithNoLocking,
  90. } EOUpdateStrategy;
  91.  
  92. @interface EODatabaseContext:EOCooperatingObjectStore
  93. {
  94.     EODatabase *_database;
  95.     EOAdaptorContext *_adaptorContext;
  96.     EOUpdateStrategy _updateStrategy;
  97.     NSMutableArray *_uniqueStack;
  98.     NSMutableArray *_deleteStack;
  99.     NSMutableArray *_modifiedObjects;
  100.     NSMutableArray *_registeredChannels;
  101.     NSMapTable *_dbOperationsByGlobalID;
  102.     EOObjectStoreCoordinator *_coordinator;    // not retained
  103.     EOEditingContext *_editingContext;        // not retained
  104.     void *_lockedObjects;
  105.     unsigned _currentGeneration;
  106.     unsigned _concurentFetches;
  107.     NSMutableDictionary *_batchFaultBuffer;
  108.     NSMutableDictionary *_batchToManyFaultBuffer;
  109.     id _currentBatch;
  110.     EOEntity *_lastEntity;
  111.     EOGlobalID *_currentGlobalID;
  112.     NSDictionary *_currentSnapshot;
  113.     
  114.     struct {
  115.         unsigned int preparingForSave:1;
  116.         unsigned int beganTransaction:1;
  117.     unsigned int _RESERVED:30;
  118.     } _flags;
  119.     id _delegate; // not retained
  120.     struct {
  121.         unsigned int willRunLoginPanelToOpenDatabaseChannel:1;
  122.         unsigned int newPrimaryKey:1;
  123.         unsigned int willPerformAdaptorOperations:1;
  124.         unsigned int shouldInvalidateObject:1;
  125.         unsigned int willOrderAdaptorOperations:1;
  126.         unsigned int shouldLockObject:1;
  127.         unsigned int shouldRaiseForLockFailure:1;
  128.         unsigned int shouldFetchObjects:1;
  129.         unsigned int didFetchObjects:1;
  130.         unsigned int _RESERVED:23;
  131.     } _delegateRespondsTo;
  132. }
  133.  
  134. - initWithDatabase:(EODatabase *)database;
  135.     // Initializes a newly allocated EODatabaseContext with database as the
  136.     // EODatabase object it works with.  Returns self, or nil if no more
  137.     // contexts can be associated with database.
  138.  
  139. + (EODatabaseContext *)registeredDatabaseContextForModel:(EOModel *)model editingContext:(EOEditingContext *)editingContext;
  140.     // Finds the objectStoreCoordinator for the editingContext and checks to see
  141.     // it already contains a EODatabaseContext cooperating object store for this
  142.     // model. If it does, it returns that context, otherwise it instantiates
  143.     // a new context, adds it to the coordinator, and returns it.
  144.  
  145. + (Class)contextClassToRegister;
  146. + (void)setContextClassToRegister:(Class)contextClass;
  147.     // When an EOObjectStoreCoordinator sends an EOCooperatingObjectStoreNeeded
  148.     // notification for an entity in the default model group, if
  149.     // contextClassToRegister is non-nil, an instance of this class is
  150.     // created, the model for the entity is registered, and the
  151.     // context is registered with the requesting ObjectStoreCoordinator.
  152.     // By default this class is EODatabaseContext, but its can be overridden
  153.     // with subclasses.
  154.  
  155. - (BOOL)hasBusyChannels;
  156.     // Returns YES if the receiver has channels that have outstanding
  157.     // operations (that is, have a fetch in progress), NO otherwise.
  158.  
  159. - (NSArray *)registeredChannels;
  160.     // Returns an array containing all channels that have been registered for
  161.     // use with this context;
  162.  
  163. - (void)registerChannel:(EODatabaseChannel *)channel;
  164. - (void)unregisterChannel:(EODatabaseChannel *)channel;
  165.     // Registers or unregisters a channel with a EODatabaseContext.
  166.     // The given channel is added or removed from the availableChannel pool
  167.     // used to service fetch and fault requests.
  168.     // Registered channels are retained by the context.
  169.  
  170. - (EODatabaseChannel *)availableChannel;
  171.     // This method checks its list of channels and if it finds one that
  172.     // is not busy it returns it. Otherwise, it posts an
  173.     // EODatabaseChannelNeededNotification with the hope that someone will
  174.     // provide a new channel. After posting the notification, the context
  175.     // checks its list of channels again. If there are still no available
  176.     // channels and the list is completely empty, the context creates one
  177.     // itself, however if the list is not empty and there are no available
  178.     // channels, the method returns nil.
  179.  
  180. - (EODatabase *)database;
  181.     // Returns the EODatabase that the context works with.
  182.  
  183. - (EOObjectStoreCoordinator *)coordinator;
  184.     // Returns the context's coordinator or nil if there is none.
  185.  
  186. - (EOAdaptorContext *)adaptorContext;
  187.     // Returns the EOAdaptorContext used by the EODatabaseContext for
  188.     // communication with the database server.
  189.  
  190. - (void)setUpdateStrategy:(EOUpdateStrategy)strategy;
  191. - (EOUpdateStrategy)updateStrategy;
  192.     // These methods set/return the update strategy used by the context.  The
  193.     // default is EOUpdateWithOptimisticLocking.
  194.  
  195. - (id)delegate;
  196. - (void)setDelegate:(id)delegate;
  197.     // Propagates the delegate to all of its channels.
  198. @end
  199.  
  200. @interface EODatabaseContext(EOObjectStoreSupport)
  201. // The EODatabaseContext is an ObjectStore for relational-style databases
  202.  
  203. - (id)faultForGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)context;
  204.     // Creates a to-one fault and register it in the editing context.
  205.  
  206. - (NSArray *)arrayFaultWithSourceGlobalID:(EOGlobalID *)globalID relationshipName:(NSString *)name editingContext:(EOEditingContext *)context;
  207.     // Create a to-many fault.  The relationshipName must correspond to an EORelationship in
  208.     // the EOEntity for the given globalID.
  209.  
  210. - (void)initializeObject:(id)object withGlobalID:(EOGlobalID *)globalID
  211.           editingContext:(EOEditingContext *)context;
  212.     // Initializes the given instance by filling it with properties based on
  213.     // row data fetched from the adaptor.  The snapshot for the given globalID is
  214.     // looked up and those attributes in the snapshot that are marked as class
  215.     // properties in the EOEntity are assigned to the EO.  For relationship
  216.     // class properties, faults are constructed and assigned to the object.
  217.  
  218. - (NSArray *)objectsForSourceGlobalID:(EOGlobalID *)globalID relationshipName:(NSString *)name editingContext:(EOEditingContext *)context;
  219.     // This method is used to fire a to-many fault.  The snapshot for the source object
  220.     // is located and the EORelationship corresponding to relationshipName is used to
  221.     // construct a qualifier from that snapshot.  This qualifier is the used to
  222.     // fetch the requested objects using objectsWithFetchSpecification:editingContext:
  223.  
  224. - (void)refaultObject:object withGlobalID:(EOGlobalID *)globalID editingContext:(EOEditingContext *)context;
  225.     // Turn the given Enterprise Object back into a fault.
  226.  
  227. - (void)saveChangesInEditingContext:(EOEditingContext *)context;
  228.     // Sent by an EditingContext to its ObjectStore to commit changes.
  229.     // Normally the EODatabaseContext is not called directly by this method
  230.     // but is instead called by an EOObjectStoreCoordinator.
  231.  
  232. - (NSArray *)objectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification editingContext:(EOEditingContext *)context;
  233.     // The base method to fetch an array of objects into the given context.
  234.     // The database context obtains an available EODatabaseChannel and issues
  235.     // a fetch with the given fetch specification.
  236.     // Raises an exception if an error occurs.
  237.  
  238. - (BOOL)isObjectLockedWithGlobalID:(EOGlobalID *)gid editingContext:(EOEditingContext *)context;
  239.     // Returns YES if the row corresponding to the given globalID has been locked in
  240.     // an open transaction held by this context.
  241.  
  242. - (void)lockObjectWithGlobalID:(EOGlobalID *)gid editingContext:(EOEditingContext *)context;
  243.     // Locks that database row corresponding to this globalID in the underlying
  244.     // database server.  If a transaction is not already open at the time of the
  245.     // lock request, the transaction is begun and is held open until either
  246.     // saveChangesInEditingContext: or invalidateAllObjects is called.
  247.     // At that point all locks are released.
  248.  
  249. - (void)invalidateAllObjects;
  250. - (void)invalidateObjectsWithGlobalIDs:(NSArray *)globalIDs;
  251.     // This will discard the snapshots for the given globalIDs an broadcast an
  252.     // invalidation notification which will cause an EditingContext containing
  253.     // objects fetched from this context to refault those objects.  The result
  254.     // is that these objects will be refetched from the database the next time
  255.     // they are accessed.
  256. @end
  257.  
  258.  
  259. @interface EODatabaseContext(EOCooperatingObjectStoreSupport)
  260. // The EODatabaseContext is a CooperatingObjectStore, meaning it
  261. // can work in concert with other CooperatingObjectStores (including
  262. // other EODatabaseContexts) to provide unified access to multiple databases
  263. // under a single EOObjectStoreCoordinator
  264.  
  265. - (BOOL)ownsGlobalID:(EOGlobalID *)globalID;
  266.     // Returns YES if the gloablID is the type created by the DatabaseContext
  267.     // and if for an entity serviced by this context.
  268.  
  269. - (BOOL)ownsObject:(id)object;
  270.     // Returns yes if one of the Entities in the models for this databaseContext
  271.     // creates objects of this class.
  272.  
  273. - (BOOL)handlesFetchSpecification:(EOFetchSpecification *)fetchSpecification;
  274.     // returns yes if the entity identified by the entityName in this fetchSpecification
  275.     // can be found in one of the models owned by theis context's EODatabase.
  276.  
  277. - (void)prepareForSaveWithCoordinator:(EOObjectStoreCoordinator *)coordinator editingContext:(EOEditingContext *)context;
  278.     // Prepares to save changes.  Obtains primary keys for any inserted objects
  279.     // in the EditingContext that are owned by this context.
  280.  
  281. - (void)recordChangesInEditingContext;
  282.     // Contructs a list of EODatabaseOperations for all changes in the EditingContext
  283.     // that are owned by this context.  Forward any relationship changes discovered
  284.     // but not owned by this context to the coordinator.
  285.  
  286. - (void)recordUpdateForObject:object changes:(NSDictionary *)changes;
  287.     // Applies changes supplied by another context to the DatabaseOperation
  288.     // for that object in this context.
  289.  
  290. - (void)performChanges;
  291.     // Contructs EOAdaptorOperations for all EODatabaseOperations constructed in
  292.     // during recordChangesInEditingContext and recordUpdateForObject:changes:.
  293.     // Performs the EOAdaptorOperations on an available adaptor channel.
  294.     // If the save succeeds, updates the snapshots in the EODatabasContext to reflect
  295.     // the new state of the server.
  296.     // Raises an exception is the adaptor is unable to perform the operations.
  297.  
  298. - (void)commitChanges;
  299.     // Instructs the adaptor to commit the transaction.  If the commit is
  300.     // successful, any primary and foreign key changes are written back to the
  301.     // saved objects, database locks are released, and an EOObjectsChangedInStore
  302.     // notification is posted describing the committed changes.
  303.     // Raises an exception if the adaptor is unable to commit the transaction.
  304.  
  305. - (void)rollbackChanges;
  306.     // Instruct the adaptor to rollbackTransaction.
  307.     // Rolls back and changed snapshots, and released all locks.
  308.  
  309. - (NSDictionary *)valuesForKeys:(NSArray *)keys object:object;
  310.     // Returns properties from the snapshot of the given object.  These are used
  311.     // primarily by another context to extract foreign key properties for objects
  312.     // in this context.
  313. @end
  314.  
  315.  
  316. @interface EODatabaseContext(EOBatchFaulting)
  317.  
  318. - (void)batchFetchRelationship:(EORelationship *)relationship forSourceObjects:(NSArray *)objects editingContext:(EOEditingContext *)editingContext;
  319.     // Clear all the faults for the relationship pointed by the source objects and
  320.     // make sure to perform only a single, efficient, fetch (two fetches if the
  321.     // relationship is many to many).
  322.  
  323. @end
  324.  
  325. // The snapshotting methods on the context are for maintaining snapshots and
  326. // information about which snapshots are locked during a transaction.
  327.  
  328. @interface EODatabaseContext (EODatabaseSnapshotting)
  329.  
  330. - (void)recordSnapshot:(NSDictionary *)snapshot forGlobalID:(EOGlobalID *)gid;
  331.     // records the database row snapshow the given GlobalID.
  332.  
  333. - (NSDictionary *)snapshotForGlobalID:(EOGlobalID *)gid;
  334.     // Returns the snapshot assocated with GlobalID, if there is one; else
  335.     // returns nil.  Searches first locally (in the transaction scope)
  336.     // and then in the EODatabase.
  337.  
  338. - (NSDictionary *)localSnapshotForGlobalID:(EOGlobalID *)gid;
  339.     // Returns the snapshot assocated with GlobalID, if there is one; else
  340.     // returns nil.  Only searches locally (in the transaction scope)
  341.     // and, not in the EODatabase.
  342.  
  343. - (void)forgetSnapshotForGlobalID:(EOGlobalID *)gid;
  344. - (void)forgetSnapshotsForGlobalIDs:(NSArray *)gids;
  345.  
  346. - (void)recordSnapshots:(NSDictionary *)snapshots;
  347.     // record a bunch of snapshots from a dictionary keyed by Global ID
  348.  
  349. - (void)registerLockedObjectWithGlobalID:(EOGlobalID *)globalID;
  350. - (BOOL)isObjectLockedWithGlobalID:(EOGlobalID *)globalID;
  351. - (void)forgetAllLocks;
  352. - (void)forgetLocksForObjectsWithGlobalIDs:(NSArray *)gids;
  353.  
  354. @end
  355.  
  356.  
  357. // Notifications:
  358. EOACCESS_EXTERN NSString *EODatabaseChannelNeededNotification;
  359.     // This nofification is broadcast whenever an EODatabaseContext is asked to perform an object
  360.     // store operation and it doesn't have an available databaseChannel. Subscribers can create
  361.     // a new channel and add it to the databaseContext at this time.
  362.  
  363. @interface NSObject (EODatabaseContextDelegation)
  364.  
  365. - (BOOL)databaseContext:(EODatabaseContext *)context willRunLoginPanelToOpenDatabaseChannel:(EODatabaseChannel *)channel;
  366.     // When the databaseContext is about to use a channel, it checks to see if the
  367.     // databaseChannel's corresponding adaptorChannel is open. If it is not, it
  368.     // attempts to open the adaptorChannel by sending it an openChannel message.
  369.     // If that doesn't succeed, the databaseContext will ask the adaptorChannel's
  370.     // adaptor to run the login panel and open the channel. The database context
  371.     // gives the delegate a chance to intervene in this by invoking this delegate
  372.     // method. The delegate can return NO to stop the databaseContext from
  373.     // running the login panel. In this case, the delegate is responsible for
  374.     // opening the channel. If the delegate returns YES, the databaseContext
  375.     // will run the login panel.
  376.  
  377. - (NSDictionary *)databaseContext:(EODatabaseContext *)context newPrimaryKeyForObject:(id)object entity:(EOEntity *)entity;
  378.     // If a newly inserted EO doesn't already have have a primary key set,
  379.     // this delegate is called to generate a key.  If the delegate is not implemented,
  380.     // or returns nil, then the DatabaseContext will call
  381.     // [EOAdaptorChannel primaryKeyForNewRowWithEntity:(EOEntity *)entity]
  382.     // to attempt to generate the key.
  383.  
  384. - (BOOL)databaseContext:(EODatabaseContext *)context failedToFetchObject:(id)object globalID:(EOGlobalID *)gid;
  385.     // Called when a toOne fault cannot find its data in the database. The object is a cleared fault.
  386.     // If this method returns YES, the DatabaseContext assume that the delegate set the information
  387.     // into the object. If it returns NO, the DatatabaseContext will raise the error.
  388.  
  389. - (NSArray *)databaseContext:(EODatabaseContext *)context willOrderAdaptorOperationsFromDatabaseOperations:(NSArray *)databaseOps;
  390.     // If the delegate responds to this message, it must return an array of adaptor
  391.     // operations. The delegate can fabricate its own array by asking each
  392.     // databaseOperation for its list of adaptor operations and adding them to the
  393.     // array which will eventually be returned by this method. Of course, the delegate
  394.     // is free to optimize, order, or transform the list in whatever way it deems necessary.
  395.  
  396. - (NSArray *)databaseContext:(EODatabaseContext *)context willPerformAdaptorOperations:(NSArray *)adaptorOps adaptorChannel:(EOAdaptorChannel *)adaptorChannel;
  397.     // The delegate can return a new adaptorOps array which the databaseContext
  398.     // will use in place of the old one. This is useful for applications that
  399.     // may need a special ordering of the adaptor operations so as not to violate
  400.     // any database constraints that may exist.
  401.  
  402. - (BOOL)databaseContext:(EODatabaseContext *)context shouldInvalidateObjectWithGlobalID:(EOGlobalID *)globalId snapshot:(NSDictionary *)snapshot;
  403.     // Delegate can cause the object to not be invalidated by returning NO.
  404.  
  405. - (NSArray *)databaseContext:(EODatabaseContext *)context shouldFetchObjectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification editingContext:(EOEditingContext *)editingContext;
  406.     // Called by objectsWithFetchSpecification:editingContext: to give the delegate the
  407.     // opportunity to satisfy the fetch request from a local cache.
  408.     // If delegate returns nil, the databaseContext with perform the fetch.  Otherwise,
  409.     // the returned array is returned as the fetch result.
  410.  
  411. - (void)databaseContext:(EODatabaseContext *)context didFetchObjects:(NSArray *)objects fetchSpecification:(EOFetchSpecification *)fetchSpecification editingContext:(EOEditingContext *)editingContext;
  412.     // Called by objectsWithFetchSpecification:editingContext: after fetching objects.
  413.  
  414. // These 4 delegate methods are actually sent by the channel, but are placed
  415. // here for ease of access. The context and it's channels always have the
  416. // same delegate.
  417. - (BOOL)databaseContext:(EODatabaseContext *)context shouldSelectObjectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification databaseChannel:(EODatabaseChannel *)channel;
  418.     // Invoked from -[EODatabaseChannel selectObjectsDescribedByQualifier:...] to tell the
  419.     // delegate that the channel will select objects as specified by
  420.     // qualifier.  The delegate should not modify the qualifier or fetch order.
  421.     // If the delegate returns YES the channel will go ahead and select the
  422.     // object; if the delegate returns NO the channel will skip the select
  423.     // and return.
  424.  
  425. - (BOOL)databaseContext:(EODatabaseContext *)context shouldUsePessimisticLockWithFetchSpecification:(EOFetchSpecification *)fetchSpecification databaseChannel:(EODatabaseChannel *)channel;
  426.     // Invoked from -[EODatabaseChannel -selectObjectsDescribedByQualifier:...] when
  427.     // pessimistic locking is the update strategy specified on the channels
  428.     // databaseContext. The delegate should not modify the qualifier or fetch order.
  429.     // If the delegate returns YES the channel will lock the rows being selected;
  430.     // if the delegate returns NO the channel will select the rows without locking.
  431.  
  432. - (void)databaseContext:(EODatabaseContext *)context didSelectObjectsWithFetchSpecification:(EOFetchSpecification *)fetchSpecification databaseChannel:(EODatabaseChannel *)channel;
  433.     // Invoked from -[EODatabaseChannel -selectObjectsDescribedByQualifier:...] to
  434.     // tell the delegate that the channel selected the objects as specified by the
  435.     // qualifier.
  436.  
  437. - (NSDictionary *)databaseContext:(EODatabaseContext *)context
  438.     shouldUpdateCurrentSnapshot:(NSDictionary *)currentSnapshot
  439.     newSnapshot:(NSDictionary *)newSnapshot globalID:(EOGlobalID *)globalID
  440.     databaseChannel:(EODatabaseChannel *)channel;
  441.     // Invoked from -[EODatabaseChannel fetchObject] when a row is fetched from
  442.     // the database for which the context already has a snapshot.  This method is
  443.     // called without first checking whether the snapshots are equivalent (the check
  444.     // would be too expensive to do in the common case) so the receiver may be passed
  445.     // equivalent snapshots. The default behavior is to
  446.     // not update an older snapshot. The delegate can override this behavior by
  447.     // returning a dictonary (possibly newSnapshot) that will be recorded as the 
  448.     // updated snapshot -- this will result in an  EOObjectsChangedInStoreNotification
  449.     // being posted indicating that all objects corresponding to this globalID are now
  450.     // invalid. If the delegate returns nil, the context will perform the default behavior.
  451.  
  452. - (BOOL)databaseContext:(EODatabaseContext *)databaseContext shouldLockObjectWithGlobalID:(EOGlobalID *)globalID snapshot:(NSDictionary *)snapshot;
  453.     // Invoked from -[EODatabaseContext lockObjectWithGlobalID:editingContext]. The
  454.     // delegate should return YES if it wants the method to proceed or NO to cause
  455.     // the method to return. Delegates can override the locking mechanism by implementing
  456.     // their own locking procedure and returning NO. The Override method should raise
  457.     // on failure to lock exactly one object.
  458.  
  459. - (BOOL)databaseContext:(EODatabaseContext *)databaseContext shouldRaiseExceptionForLockFailure:(NSException *)exception;
  460.     // Invoked from -[EODatabaseContext lockObjectWithGlobalID:editingContext:]. This
  461.     // method allows the delegate to suppress an exception that has occurred during the
  462.     // attempt to lock the object.
  463.  
  464. @end
  465.  
  466. EOACCESS_EXTERN NSString *EOPrefetchingRelationshipHintKey;
  467.     // This key can be used in the hints dictionary of an EOFetchSpecification
  468.     // passed to the -objectsWithFetchSpecification:editingContext: method.
  469.     // The value is an array of relationship paths that should be prefetched
  470.     // along with the main fetch.  For example, if fetching from the Movie
  471.     // entity, you might specify paths of the form "(directors, roles.talent, plotSummary)".
  472.     //
  473.  
  474. EOACCESS_EXTERN NSString *EOCustomQueryExpressionHintKey;
  475.     // This key can be used in the hints dictionary of an EOFetchSpecification
  476.     // passed to the -objectsWithFetchSpecification:editingContext: method.
  477.     // It should contain a SQL string for performing the fetch.  The
  478.     // expression must query the the exact same attributes in the same order
  479.     // as EOF would query if generating the SELECT expression dynamically.
  480.     // If this key is supplied, other aspects of the EOFetchSpecification such
  481.     // as isDeep, qualifier, and sortOrderings are ignored (in that sense this
  482.     // key is more of a directive than a hint).
  483.     
  484.