25#import "CoreDataHeaders.h"
27id NSErrorMergePolicy = nil,
28 NSMergeByPropertyStoreTrumpMergePolicy = nil,
29 NSMergeByPropertyObjectTrumpMergePolicy = nil,
30 NSOverwriteMergePolicy = nil,
31 NSRollbackMergePolicy = nil;
41RemoveKVOSetupFromObjects(
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
74@interface NSManagedObjectContext (GSCoreDataInternal)
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);
242 NSManagedObject * object;
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
327 NSManagedObject * object;
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])
346 GSPersistentStore * store = [_storeCoordinator
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);
436- (NSManagedObject *) objectRegisteredForID: (NSManagedObjectID *) objectID
439 NSManagedObject * object;
441 e = [_registeredObjects objectEnumerator];
442 while ((
object = [e nextObject]) != nil)
444 if ([[
object objectID] _isEqualToManagedObjectID: objectID] == YES)
461- (NSManagedObject *) objectWithID: (NSManagedObjectID *) objectID
463 NSManagedObject * object;
465 object = [
self objectRegisteredForID: objectID];
470 NSManagedObject * object;
473 _initAsFaultWithObjectID: objectID ownedByContext:
self]
475 [
self _registerObject: object];
502- (NSArray *) executeFetchRequest: (NSFetchRequest *) request
503 error: (NSError **) error
505 NSEntityDescription * entity = [request
entity];
506 NSPredicate * predicate = [request
predicate];
508 NSMutableArray * fetchedObjects;
510 NSManagedObject * object;
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];
568- (void) insertObject: (NSManagedObject *) object
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
609- (void) deleteObject: (NSManagedObject *) object
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
659 NSManagedObject *
object = anObject;
660 GSPersistentStore * store = aPersistentStore;
661 NSManagedObjectID * oldObjectID, * newObjectID;
663 if (![
object isKindOfClass: [NSManagedObject
class]])
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];
737- (void) refreshObject: (NSManagedObject *) object
738 mergeChanges: (BOOL) mergeChanges
740 NSManagedObjectID * objectID = [object
objectID];
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);
942@implementation NSManagedObjectContext (GSCoreDataPrivate)
955 changedValueForSingleKey: (NSString *) key
956 oldValue: (
id) oldValue
957 newValue: (
id) newValue
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];
1017@implementation NSManagedObjectContext (GSCoreDataInternal)
1019- (void) _setFetchedPropertyValues: (NSDictionary *) newPropertyValues
1021 mergeChanges: (BOOL) mergeChanges
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)
1045 if ([property isTransient])
1047 if (mergeChanges == NO)
1055 if (newValue == nil)
1059 else if ([property isKindOfClass: relationshipClass])
1073 [
object _flushChangedValues];
1075 if (mergeChanges == YES)
1079 while ((key = [e nextObject]) != nil)
1086- (void) _setRelationship: (NSRelationshipDescription *) relationship
1087 fetchedValue: (
id) value
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);
1110 e = [
value objectEnumerator];
1111 while ((destinationID = [e nextObject]) != nil)
1113 destinationObject = [
self objectWithID: destinationID];
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];
1147 [
tmp makeObjectsPerformSelector: @selector(release)];
1157 if (_retainsRegisteredObjects == NO)
1162 if ([_registeredObjects containsObject:
object] == NO)
1174- (void) _unregisterObjects: (NSSet *) objects
1176 if (_retainsRegisteredObjects == NO)
1180 tmp = [[
objects mutableCopy] autorelease];
1182 [
tmp intersectSet: _registeredObjects];
1185 [
tmp makeObjectsPerformSelector: @selector(retain)];
1196 if (_retainsRegisteredObjects)
1198 if ([_registeredObjects containsObject:
object] == YES)
1213NSString *
const NSManagedObjectContextObjectsDidChangeNotification =
1214 @"NSManagedObjectContextObjectsDidChangeNotification";
1215NSString *
const NSManagedObjectContextDidSaveNotification =
1216 @"NSManagedObjectContextDidSaveNotification";
1218NSString *
const NSInsertedObjectsKey =
@"NSInsertedObjectsKey";
1219NSString *
const NSUpdatedObjectsKey =
@"NSUpdatedObjectsKey";
1220NSString *
const NSDeletedObjectsKey =
@"NSDeletedObjectsKey";
Internal methods methods of GNUstep Core Data for NSManagedObjectContext.
void _setRelationship:fetchedValue:ofObject:(NSRelationshipDescription *relationship,[fetchedValue] id value,[ofObject] NSManagedObject *object)
Sets the relationship described by ‘relationship’ in ‘object’ to ‘value’.
Private methods of GNUstep Core Data for NSManagedObjectContext.
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.