mirror of
https://github.com/zhigang1992/RestKit.git
synced 2026-04-22 11:46:05 +08:00
add support to core data component to hook up relationships from foreign keys present in the server payload
This commit is contained in:
@@ -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
|
||||
*/
|
||||
|
||||
@@ -147,6 +147,10 @@
|
||||
return [NSDictionary dictionary];
|
||||
}
|
||||
|
||||
+ (NSDictionary*)relationshipToPrimaryKeyPropertyMappings {
|
||||
return [NSDictionary dictionary];
|
||||
}
|
||||
|
||||
#pragma mark Helpers
|
||||
|
||||
- (id)primaryKeyValue {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user