add support to core data component to hook up relationships from foreign keys present in the server payload

This commit is contained in:
Jeff Arena
2010-10-27 17:00:31 -07:00
parent 8dbd8c5d69
commit 57e2403624
5 changed files with 88 additions and 28 deletions

View File

@@ -105,6 +105,24 @@
*/
+ (id)objectWithPrimaryKeyValue:(id)value;
/**
* Must return a dictionary mapping Core Data relationships for the managed object
* to their corresponding primary key properties on the managed object. Must
* return an empty dictionary if there are no relationships to be mapped.
*
* For example, given a Project object associated with a user, where the user is
* specified by a userId property on the managed object:
*
* [NSDictionary dictionaryWithObject:@"userId" forKey:@"user"];
* Will hydrate the 'user' association on the managed object with the object
* in the local object graph having the primary key specified in the managed object's
* userId property.
*
* In effect, this approach allows foreign key relationships between managed objects
* to be automatically maintained from the server to the underlying Core Data object graph.
*/
+ (NSDictionary*)relationshipToPrimaryKeyPropertyMappings;
/**
* Returns the value of the primary key property for this object
*/

View File

@@ -147,6 +147,10 @@
return [NSDictionary dictionary];
}
+ (NSDictionary*)relationshipToPrimaryKeyPropertyMappings {
return [NSDictionary dictionary];
}
#pragma mark Helpers
- (id)primaryKeyValue {

View File

@@ -7,6 +7,7 @@
//
#import <CoreData/CoreData.h>
#import "RKManagedObject.h"
#import "RKManagedObjectCache.h"
/**
@@ -57,4 +58,13 @@ extern NSString* const RKManagedObjectStoreDidFailSaveNotification;
*/
- (NSArray*)objectsWithIDs:(NSArray*)objectIDs;
/**
* Retrieves a model object from the object store given the model object's class and
* the primaryKeyValue for the model object. This method leverages techniques specific to
* Core Data for optimal performance. The return value will be nil in cases where an existing
* object cannot be found in the object store.
*/
- (RKManagedObject*)findInstanceOfManagedObject:(Class)class withPrimaryKeyValue:(id)primaryKeyValue;
@end

View File

@@ -186,4 +186,31 @@ static NSString* const kRKManagedObjectContextKey = @"RKManagedObjectContext";
return objectArray;
}
- (RKManagedObject*)findInstanceOfManagedObject:(Class)class withPrimaryKeyValue:(id)primaryKeyValue {
RKManagedObject* object = nil;
if ([class respondsToSelector:@selector(allObjects)]) {
NSArray* objects = nil;
NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary];
if (nil == [threadDictionary objectForKey:class]) {
NSFetchRequest* fetchRequest = [class fetchRequest];
[fetchRequest setReturnsObjectsAsFaults:NO];
objects = [class objectsWithFetchRequest:fetchRequest];
NSLog(@"Cacheing all %d %@ objects to thread local storage", [objects count], class);
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
NSString* primaryKey = [class performSelector:@selector(primaryKeyProperty)];
for (id theObject in objects) {
id primaryKeyValue = [theObject valueForKey:primaryKey];
[dictionary setObject:theObject forKey:primaryKeyValue];
}
[threadDictionary setObject:dictionary forKey:class];
}
NSMutableDictionary* dictionary = [threadDictionary objectForKey:class];
object = [dictionary objectForKey:primaryKeyValue];
}
return object;
}
@end

View File

@@ -240,36 +240,13 @@ static const NSString* kRKModelMapperMappingFormatParserKey = @"RKMappingFormatP
// Persistent Instance Finders
- (id)findOrCreateInstanceOfModelClass:(Class)class fromElements:(NSDictionary*)elements {
NSArray* objects = nil;
id object = nil;
// TODO: Core Data dependency... Push into objectStore
if ([class respondsToSelector:@selector(allObjects)]) {
NSMutableDictionary* threadDictionary = [[NSThread currentThread] threadDictionary];
if (nil == [threadDictionary objectForKey:class]) {
NSFetchRequest* fetchRequest = [class fetchRequest];
[fetchRequest setReturnsObjectsAsFaults:NO];
objects = [class objectsWithFetchRequest:fetchRequest];
NSLog(@"Cacheing all %d %@ objects to thread local storage", [objects count], class);
NSMutableDictionary* dictionary = [NSMutableDictionary dictionary];
NSString* primaryKey = [class performSelector:@selector(primaryKeyProperty)];
for (id theObject in objects) {
id primaryKeyValue = [theObject valueForKey:primaryKey];
[dictionary setObject:theObject forKey:primaryKeyValue];
}
[threadDictionary setObject:dictionary forKey:class];
}
NSMutableDictionary* dictionary = [threadDictionary objectForKey:class];
if ([class respondsToSelector:@selector(objectWithPrimaryKeyValue:)]) {
NSString* primaryKeyElement = [class performSelector:@selector(primaryKeyElement)];
id primaryKeyValue = [elements objectForKey:primaryKeyElement];
object = [dictionary objectForKey:primaryKeyValue];
}
if ([class respondsToSelector:@selector(primaryKeyElement)]) {
NSString* primaryKeyElement = [class performSelector:@selector(primaryKeyElement)];
id primaryKeyValue = [elements objectForKey:primaryKeyElement];
object = [[[RKObjectManager sharedManager] objectStore] findInstanceOfManagedObject:class
withPrimaryKeyValue:primaryKeyValue];
}
// instantiate if object is nil
if (object == nil) {
if ([class respondsToSelector:@selector(object)]) {
@@ -392,6 +369,30 @@ static const NSString* kRKModelMapperMappingFormatParserKey = @"RKMappingFormatP
[object setValue:child forKey:propertyName];
}
}
if ([object isKindOfClass:[RKManagedObject class]]) {
RKManagedObject* managedObject = (RKManagedObject*)object;
NSDictionary* relationshipToPkPropertyMappings = [[managedObject class] relationshipToPrimaryKeyPropertyMappings];
for (NSString* relationship in relationshipToPkPropertyMappings) {
NSString* primaryKeyPropertyString = [relationshipToPkPropertyMappings objectForKey:relationship];
NSNumber* objectPrimaryKeyValue = nil;
@try {
objectPrimaryKeyValue = [managedObject valueForKeyPath:primaryKeyPropertyString];
} @catch (NSException* e) {
NSLog(@"Caught exception:%@ when trying valueForKeyPath with path:%@ for object:%@", e, primaryKeyPropertyString, managedObject);
}
NSDictionary* relationshipsByName = [[managedObject entity] relationshipsByName];
NSEntityDescription* relationshipDestinationEntity = [[relationshipsByName objectForKey:relationship] destinationEntity];
id relationshipDestinationClass = objc_getClass([[relationshipDestinationEntity managedObjectClassName] cStringUsingEncoding:NSUTF8StringEncoding]);
RKManagedObject* relationshipValue = [[[RKObjectManager sharedManager] objectStore] findInstanceOfManagedObject:relationshipDestinationClass
withPrimaryKeyValue:objectPrimaryKeyValue];
if (relationshipValue) {
[managedObject setValue:relationshipValue forKey:relationship];
}
}
}
}
- (void)updateModel:(id)model fromElements:(NSDictionary*)elements {