25 #import "CoreDataHeaders.h"
27 id NSErrorMergePolicy = nil,
28 NSMergeByPropertyStoreTrumpMergePolicy = nil,
29 NSMergeByPropertyObjectTrumpMergePolicy = nil,
30 NSOverwriteMergePolicy = nil,
31 NSRollbackMergePolicy = nil;
41 RemoveKVOSetupFromObjects(
id observer, NSSet * objects)
43 NSEnumerator * e = [objects objectEnumerator];
46 while ((
object = [e nextObject]) != nil)
48 NSEntityDescription * entity;
51 for (entity = [
object entity];
53 entity = [entity superentity])
55 NSEnumerator * propertyEnum = [[entity properties]
57 NSPropertyDescription * property;
59 while ((property = [propertyEnum nextObject]) != nil)
61 [object removeObserver: observer
62 forKeyPath: [property name]];
68 @interface GSMergePolicy : NSObject
71 @implementation GSMergePolicy
84 - (void) _setFetchedPropertyValues: (NSDictionary *) propertyValues
86 mergeChanges: (BOOL) mergeChanges;
95 - (void) _setRelationship: (NSRelationshipDescription *) relationship
96 fetchedValue: (
id) value
104 - (void) _registerObjects: (NSSet *) objects;
116 - (void) _unregisterObjects: (NSSet *) objects;
132 @implementation NSManagedObjectContext
136 if (NSErrorMergePolicy == nil)
153 TEST_RELEASE(_storeCoordinator);
155 TEST_RELEASE(_registeredObjects);
156 TEST_RELEASE(_insertedObjects);
157 TEST_RELEASE(_updatedObjects);
158 TEST_RELEASE(_deletedObjects);
160 TEST_RELEASE(_undoManager);
161 TEST_RELEASE(_mergePolicy);
168 if ((
self = [super init]))
170 _lock = [NSRecursiveLock new];
171 _undoManager = [NSUndoManager new];
173 _registeredObjects = [NSMutableSet new];
174 _insertedObjects = [NSMutableSet new];
175 _updatedObjects = [NSMutableSet new];
176 _deletedObjects = [NSMutableSet new];
177 ASSIGN(_mergePolicy, NSErrorMergePolicy);
186 - (NSPersistentStoreCoordinator *) persistentStoreCoordinator
188 return _storeCoordinator;
198 - (void) setPersistentStoreCoordinator: (NSPersistentStoreCoordinator *)
201 ASSIGN(_storeCoordinator, coordinator);
207 - (NSUndoManager *) undoManager
217 - (void) setUndoManager: (NSUndoManager *) aManager
219 ASSIGN(_undoManager, aManager);
245 [_undoManager removeAllActions];
248 RemoveKVOSetupFromObjects(
self, _insertedObjects);
249 [_insertedObjects removeAllObjects];
250 RemoveKVOSetupFromObjects(
self, _deletedObjects);
251 [_deletedObjects removeAllObjects];
254 e = [_registeredObjects objectEnumerator];
255 while ((
object = [e nextObject]) != nil)
257 if ([
object isFault] == NO)
259 NSDictionary * commitedValues = [object commitedValuesForKeys: nil];
260 NSEnumerator * commitedValuesEnumerator = [[commitedValues allKeys]
264 while ((key = [commitedValuesEnumerator nextObject]) != nil)
290 [
self _unregisterObjects: _registeredObjects];
292 [_insertedObjects removeAllObjects];
293 [_updatedObjects removeAllObjects];
294 [_deletedObjects removeAllObjects];
297 [_undoManager removeAllActions];
312 - (BOOL) save: (NSError **) errorPtr
328 NSMutableSet * objectsToSave;
329 NSError * error = nil;
331 if (_storeCoordinator == nil)
333 [NSException raise: NSInternalInconsistencyException
335 _(@"-[NSManagedObjectContext save:]: Cannot save a managed "
336 @"object context which isn't connected to a persistent store "
341 e = [_insertedObjects objectEnumerator];
342 while ((
object = [e nextObject]) != nil)
344 if ([[
object objectID] isTemporaryID])
347 persistentStoreContainingEntity: [object
entity]];
351 [
self assignObject: object toPersistentStore: store];
356 NSDictionary * userInfo = [NSDictionary
357 dictionaryWithObject: object
358 forKey: NSAffectedObjectsErrorKey];
359 SetNonNullError(errorPtr, [NSError
360 errorWithDomain: NSCoreDataErrorDomain
361 code: NSPersistentStoreIncompatibleSchemaError
362 userInfo: userInfo]);
370 objectsToSave = [[_updatedObjects mutableCopy] autorelease];
374 [objectsToSave unionSet: _insertedObjects];
377 [objectsToSave minusSet: _deletedObjects];
380 e = [_deletedObjects objectEnumerator];
381 while ((
object = [e nextObject]) != nil)
383 [_storeCoordinator deleteObjectWithID: [object
objectID]];
388 e = [objectsToSave objectEnumerator];
389 while ((
object = [e nextObject]) != nil)
391 if (![_mergePolicy mergeObject:
object
392 withStoreCoordinator: _storeCoordinator
395 SetNonNullError(errorPtr, error);
401 if (![_storeCoordinator commitChangesError: &error])
403 SetNonNullError(errorPtr, error);
409 [
self _unregisterObjects: _deletedObjects];
411 [_insertedObjects removeAllObjects];
412 [_updatedObjects removeAllObjects];
413 [_deletedObjects removeAllObjects];
426 return ([_updatedObjects count] > 0) ||
427 ([_insertedObjects count] > 0) ||
428 ([_deletedObjects count] > 0);
441 e = [_registeredObjects objectEnumerator];
442 while ((
object = [e nextObject]) != nil)
444 if ([[
object objectID] _isEqualToManagedObjectID: objectID] == YES)
465 object = [
self objectRegisteredForID: objectID];
473 _initAsFaultWithObjectID: objectID ownedByContext: self]
475 [
self _registerObject: object];
503 error: (NSError **) error
505 NSEntityDescription * entity = [request
entity];
506 NSPredicate * predicate = [request
predicate];
508 NSMutableArray * fetchedObjects;
512 NSMutableSet * fetchedObjectsIDs;
513 NSArray * storedObjects;
515 fetchedObjects = [NSMutableArray array];
518 e = [_registeredObjects objectEnumerator];
519 while ((
object = [e nextObject]) != nil)
522 if (ObjectMatchedByFetchRequest(
object, request) &&
523 [_deletedObjects containsObject: object] == NO)
525 [fetchedObjects addObject: object];
530 fetchedObjectsIDs = [NSMutableSet setWithCapacity: [fetchedObjects
532 e = [fetchedObjects objectEnumerator];
533 while ((
object = [e nextObject]) != nil)
535 [fetchedObjectsIDs addObject: [object
objectID]];
540 storedObjects = [_storeCoordinator _executeFetchRequest: request
541 ignoreIDs: fetchedObjectsIDs
542 stalenessInterval: _stalenessInterval
544 if (storedObjects != nil)
546 [fetchedObjects addObjectsFromArray: storedObjects];
557 return [[fetchedObjects copy] autorelease];
570 NSDictionary * userInfo;
573 if ([_deletedObjects containsObject:
object] == YES)
575 [_deletedObjects removeObject: object];
578 else if ([_registeredObjects containsObject:
object] == NO)
580 [
self _registerObject: object];
582 [_insertedObjects addObject: object];
589 [object _insertedIntoContext: self];
590 [object _setDeleted: NO];
592 [_undoManager registerUndoWithTarget: self
593 selector: @selector(deleteObject:)
596 userInfo = [NSDictionary dictionaryWithObject: [NSSet setWithObject: object]
597 forKey: NSInsertedObjectsKey];
598 [[NSNotificationCenter defaultCenter]
599 postNotificationName: NSManagedObjectContextObjectsDidChangeNotification
611 if ([_registeredObjects containsObject:
object] == YES)
613 NSDictionary * userInfo;
617 [_undoManager registerUndoWithTarget: self
618 selector: @selector(insertObject:)
622 if ([_insertedObjects containsObject:
object])
624 [
self _unregisterObject: object];
625 [_insertedObjects removeObject: object];
630 [_deletedObjects addObject: object];
633 userInfo = [NSDictionary
634 dictionaryWithObject: [NSSet setWithObject: object]
635 forKey: NSDeletedObjectsKey];
636 [[NSNotificationCenter defaultCenter]
637 postNotificationName: NSManagedObjectContextObjectsDidChangeNotification
656 - (void) assignObject: (
id) anObject toPersistentStore: (
id) aPersistentStore
665 [NSException raise: NSInvalidArgumentException
667 _(@"-[NSManagedObjectContext assignObject:toPersistentStore:]: "
668 @"Non-managed-object passed.")];
671 if (_storeCoordinator == nil)
673 [NSException raise: NSInternalInconsistencyException
675 _(@"-[NSManagedObjectContext assignObject:toPersistentStore:]: "
676 @"Cannot assign an object to a store in a context that isn't "
677 @"connected to a persistent store coordinator.")];
680 if (![[_storeCoordinator persistentStores] containsObject: store])
682 [NSException raise: NSInvalidArgumentException
684 _(@"-[NSManagedObjectContext assignObject:toPersistentStore:]: "
685 @"Cannot assign an object to a store which isn't in the "
686 @"persistent store with which the context in which the object "
687 @"lives is associated.")];
698 if ([_insertedObjects containsObject:
object] == NO)
700 [NSException raise: NSInvalidArgumentException
702 _(@"-[NSManagedObjectContext assignObject:toPersistentStore:]: "
703 @"Cannot assign an object to a persistent store which hasn't "
712 _initWithEntity: [oldObjectID
entity]
713 persistentStore: store
714 value: [store nextFreeIDValue]]
717 [object _setObjectID: newObjectID];
738 mergeChanges: (BOOL) mergeChanges
741 NSDictionary * propertyValues;
743 propertyValues = [_storeCoordinator fetchObjectWithID: [object
objectID]
745 cacheStalenessInterval: _stalenessInterval];
747 if (propertyValues == nil)
749 [NSException raise: NSInvalidArgumentException
751 _(@"-[NSManagedObjectContext refreshObject:mergeChanges:]: "
752 @"Cannot refresh object - data for object doesn't exist in "
753 @"the persistent store.")];
756 [
self _setFetchedPropertyValues: propertyValues
758 mergeChanges: mergeChanges];
765 - (NSSet *) insertedObjects
767 return [[_insertedObjects copy] autorelease];
774 - (NSSet *) updatedObjects
776 return [[_updatedObjects copy] autorelease];
783 - (NSSet *) deletedObjects
785 return [[_deletedObjects copy] autorelease];
791 - (NSSet *) registeredObjects
793 return [[_registeredObjects copy] autorelease];
830 return [_lock tryLock];
841 - (BOOL) retainsRegisteredObjects
843 return _retainsRegisteredObjects;
854 - (void) setRetainsRegisteredObjects: (BOOL) flag
856 if (_retainsRegisteredObjects != flag)
858 _retainsRegisteredObjects = flag;
861 if (_retainsRegisteredObjects == YES)
863 [_registeredObjects makeObjectsPerformSelector: @selector(retain)];
868 [_registeredObjects makeObjectsPerformSelector: @selector(release)];
878 - (NSTimeInterval) stalenessInterval
880 return _stalenessInterval;
891 - (void) setStalenessInterval: (NSTimeInterval) timeInterval
893 _stalenessInterval = timeInterval;
924 - (void) setMergePolicy: (
id) policy
926 if (![policy isKindOfClass: [GSMergePolicy
class]])
928 [NSException raise: NSInvalidArgumentException
929 format: _(@"-[NSManagedObjectContext setMergePolicy:]: "
930 @"Invalid merge policy (%@) specified."), policy];
933 ASSIGN(_mergePolicy, policy);
955 changedValueForSingleKey: (NSString *) key
956 oldValue: (
id) oldValue
957 newValue: (
id) newValue
959 [[_undoManager prepareWithInvocationTarget: object]
960 setValue: oldValue forKey: key];
975 changedValueForMultiKey: (NSString *) key
976 oldValue: (NSSet *) oldValue
977 setMutation: (NSKeyValueSetMutationKind) mutationKind
978 usingObjects: (NSSet *) objects
980 NSMutableSet * newValue = [object mutableSetValueForKey: key];
982 id um = [_undoManager prepareWithInvocationTarget: newValue];
984 switch (mutationKind)
986 case NSKeyValueUnionSetMutation:
989 NSMutableSet *ms = [[objects mutableCopy] autorelease];
990 [ms minusSet: oldValue];
994 case NSKeyValueMinusSetMutation:
997 NSMutableSet *ms = [[objects mutableCopy] autorelease];
998 [ms intersectSet: oldValue];
1002 case NSKeyValueIntersectSetMutation:
1003 [um unionSet: oldValue];
1005 case NSKeyValueSetSetMutation:
1006 [um setSet: oldValue];
1019 - (void) _setFetchedPropertyValues: (NSDictionary *) newPropertyValues
1021 mergeChanges: (BOOL) mergeChanges
1023 Class relationshipClass = [NSRelationshipDescription class];
1024 NSEntityDescription * entity;
1025 NSDictionary * changedValues;
1029 if (mergeChanges == YES)
1031 changedValues = [object changedValues];
1035 for (entity = [
object entity]; entity != nil; entity = [entity superentity])
1037 NSEnumerator * e = [[entity properties] objectEnumerator];
1038 NSPropertyDescription * property;
1040 while ((property = [e nextObject]) != nil)
1042 NSString * key = [property name];
1043 id newValue = [newPropertyValues objectForKey: key];
1045 if ([property isTransient])
1047 if (mergeChanges == NO)
1055 if (newValue == nil)
1059 else if ([property isKindOfClass: relationshipClass])
1061 [
self _setRelationship: (NSRelationshipDescription*) property
1062 fetchedValue: newValue
1073 [object _flushChangedValues];
1075 if (mergeChanges == YES)
1078 e = [[changedValues allKeys] objectEnumerator];
1079 while ((key = [e nextObject]) != nil)
1081 [object
setValue: [changedValues objectForKey: key]
forKey: key];
1086 - (void) _setRelationship: (NSRelationshipDescription *) relationship
1087 fetchedValue: (
id) value
1090 NSString * key = [relationship name];
1098 if ([relationship isToMany])
1100 NSMutableSet * newRelationshipValue;
1103 NSAssert1([value isKindOfClass: [NSSet
class]] ||
1104 [value isKindOfClass: [NSArray
class]],
1105 _(
@"Encountered non-collection value (%@) from store when setting "
1106 @"a to-many relationship."), value);
1108 newRelationshipValue = [NSMutableSet setWithCapacity: [value count]];
1110 e = [value objectEnumerator];
1111 while ((destinationID = [e nextObject]) != nil)
1113 destinationObject = [
self objectWithID: destinationID];
1114 [newRelationshipValue addObject: destinationObject];
1124 _(
@"Encountered non-object-ID value (%@) from store when setting "
1125 @"a relationship."), value);
1127 destinationID = value;
1128 destinationObject = [
self objectWithID: destinationID];
1134 - (void) _registerObjects: (NSSet *) objects
1136 if (_retainsRegisteredObjects == NO)
1140 tmp = [[objects mutableCopy] autorelease];
1143 [tmp minusSet: _registeredObjects];
1146 [_registeredObjects unionSet: objects];
1147 [tmp makeObjectsPerformSelector: @selector(release)];
1151 [_registeredObjects unionSet: objects];
1157 if (_retainsRegisteredObjects == NO)
1162 if ([_registeredObjects containsObject:
object] == NO)
1164 [_registeredObjects addObject: object];
1170 [_registeredObjects addObject: object];
1174 - (void) _unregisterObjects: (NSSet *) objects
1176 if (_retainsRegisteredObjects == NO)
1180 tmp = [[objects mutableCopy] autorelease];
1182 [tmp intersectSet: _registeredObjects];
1185 [tmp makeObjectsPerformSelector: @selector(retain)];
1186 [_registeredObjects minusSet: tmp];
1190 [_registeredObjects unionSet: objects];
1196 if (_retainsRegisteredObjects)
1198 if ([_registeredObjects containsObject:
object] == YES)
1202 [_registeredObjects removeObject: object];
1207 [_registeredObjects removeObject: object];
1213 NSString *
const NSManagedObjectContextObjectsDidChangeNotification =
1214 @"NSManagedObjectContextObjectsDidChangeNotification";
1215 NSString *
const NSManagedObjectContextDidSaveNotification =
1216 @"NSManagedObjectContextDidSaveNotification";
1218 NSString *
const NSInsertedObjectsKey =
@"NSInsertedObjectsKey";
1219 NSString *
const NSUpdatedObjectsKey =
@"NSUpdatedObjectsKey";
1220 NSString *
const NSDeletedObjectsKey =
@"NSDeletedObjectsKey";
Internal methods methods of GNUstep Core Data for NSManagedObjectContext.
Private methods of GNUstep Core Data for NSManagedObjectContext.
Nn abstract superclass from which concrete implementations of various persistent store types are subc...
An object for storing details about managed object fetches.
NSEntityDescription * entity()
Returns the entity of the fetch request.
NSArray * sortDescriptors()
Returns the receiver's sort descriptors.
NSPredicate * predicate()
Returns the predicate of the receiver.
For implementation notes see "Documentation/NSManagedObjectID.txt" in the source distribution of the ...
NSEntityDescription * entity()
Returns the receiver's entity (that is, the entity of the object to which this managed object ID belo...
Validates whether value'' is a valid value forattribute'', returning YES if it is,...
void setValue:forKey:(id aValue,[forKey] NSString *aKey)
Sets the value of key ‘aKey’ to ‘aValue’ and invokes corresponding KVO methods.
NSEntityDescription * entity()
Returns the entity of the receiver.
void setPrimitiveValue:forKey:(id aPrimitiveValue,[forKey] NSString *aKey)
Sets the value for key ‘aKey’ without invoking KVO methods.
NSManagedObjectID * objectID()
Returns the object ID of the receiver.