Skip to content

Sequencing issue with core data relationships

blakewatters edited this page Aug 2, 2011 · 2 revisions

As of version 0.9.3, there is a sequencing issue with the Core Data relationship hydration feature. If you are attempting to connect relationships across objects that are created within the same payload, then the relationships may fail to connect due to order dependence. This issue is documented in Github Issue #173.

This issue will be fixed in 0.9.4, but for now you can work around it by adding the following snippet to RKManagedObjectLoader.m:

// Add NSMutableArray* _managedObjects; to the ivars
- (void)objectMapper:(RKObjectMapper*)objectMapper didMapFromObject:(id)sourceObject toObject:(id)destinationObject atKeyPath:(NSString*)keyPath usingMapping:(RKObjectMapping*)objectMapping {
    if ([objectMapping isKindOfClass:[RKManagedObjectMapping class]]) {
        if (nil == _managedObjects) {
            _managedObjects = [NSMutableArray new];
        }
        [_managedObjects addObject:destinationObject];
    }    
}

- (void)objectMapperDidFinishMapping:(RKObjectMapper*)objectMapper {
    RKObjectManager* manager = [RKObjectManager sharedManager];
    
    for (NSManagedObject* object in _managedObjects) {
        RKManagedObjectMapping* objectMapping = (RKManagedObjectMapping *)[manager.mappingProvider objectMappingForClass:[object class]];
        NSDictionary* relationshipsAndPrimaryKeyAttributes = [objectMapping relationshipsAndPrimaryKeyAttributes];
        for (NSString* relationshipName in relationshipsAndPrimaryKeyAttributes) {
            NSString* primaryKeyAttribute = [relationshipsAndPrimaryKeyAttributes objectForKey:relationshipName];
            RKObjectRelationshipMapping* relationshipMapping = [objectMapping mappingForKeyPath:relationshipName];
            id<RKObjectMappingDefinition> mapping = relationshipMapping.mapping;
            if (! [mapping isKindOfClass:[RKObjectMapping class]]) {
                RKLogWarning(@"Can only connect relationships for RKObjectMapping relationships. Found %@: Skipping...", NSStringFromClass([mapping class]));
                continue;
            }
            RKObjectMapping* objectMapping = (RKObjectMapping*)mapping;
            NSAssert(relationshipMapping, @"Unable to find relationship mapping '%@' to connect by primaryKey", relationshipName);
            NSAssert([relationshipMapping isKindOfClass:[RKObjectRelationshipMapping class]], @"Expected mapping for %@ to be a relationship mapping", relationshipName);
            NSAssert([relationshipMapping.mapping isKindOfClass:[RKManagedObjectMapping class]], @"Can only connect RKManagedObjectMapping relationships");
            NSString* primaryKeyAttributeOfRelatedObject = [(RKManagedObjectMapping*)objectMapping primaryKeyAttribute];
            NSAssert(primaryKeyAttributeOfRelatedObject, @"Cannot connect relationship: mapping for %@ has no primary key attribute specified", NSStringFromClass(objectMapping.objectClass));
            id valueOfLocalPrimaryKeyAttribute = [object valueForKey:primaryKeyAttribute];
            if (valueOfLocalPrimaryKeyAttribute) {
                id relatedObject = [objectMapping.objectClass findFirstByAttribute:primaryKeyAttributeOfRelatedObject withValue:valueOfLocalPrimaryKeyAttribute];
                [object setValue:relatedObject forKey:relationshipName];
            }
        }
    }        
    
}