RestKit Add Property Mapping and Relationship Mapping
ios, objective-c, restkit, restkit-0.20
Solution
You modal diagram shows that you have one-to-many relationship (One list has many tasks).
As far as i know, in this case you need to add relationship mapping on List entity only, no need on Task entity. Also for one-to-many relationship, you don't need to add `list` relationship under `Task` entity.
Your entities relationship should look like this
So try following
[listEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"YOUR_JSON_KEYPATH_HERE" toKeyPath:@"tasks" withMapping: taskEntityMapping]];
IMPORTANT
In above method
`FromKeyPath parameter` should be the name of your `JSON key` where the relationship starts.
`toKeyPath parameter` should be the `relationship name` that you have mentioned in Entity diagram. i.e; `tasks`.
`withMapping` should be the mapping of many entity. In you case `taskEntityMapping`
Hope this fix the issue.
Problem
Please guide me about following problem. I have two entities with relationship as shown following image I am using latest version of RestKit with iOS 7 Now in my appDelegate i am using following mapping for "List" Entity ``` NSDictionary *listObjectMapping = @{ @"listID" : @"listID", @"listName" : @"listName", @"listSyncStatus" : @"listSyncStatus" }; RKEntityMapping *listEntityMapping = [RKEntityMapping mappingForEntityForName:@"List" inManagedObjectStore:managedObjectStore]; [listEntityMapping addAttributeMappingsFromDictionary:listObjectMapping]; listEntityMapping.identificationAttributes = @[ @"listID" ]; RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:listEntityMapping method:RKRequestMethodGET pathPattern:@"/api/lists" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; [objectManager addResponseDescriptor:responseDescriptor]; //Inverse mapping, to perform a POST RKRequestDescriptor *requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[listEntityMapping inverseMapping] objectClass:[List class] rootKeyPath:nil method:RKRequestMethodPOST]; objectManager.requestSerializationMIMEType = RKMIMETypeJSON; [objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON]; [RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"application/json"]; [objectManager addRequestDescriptor:requestDescriptor]; //Inverse mapping, to perform a PUT requestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[listEntityMapping inverseMapping] objectClass:[List class] rootKeyPath:nil method:RKRequestMethodPUT]; objectManager.requestSerializationMIMEType = RKMIMETypeJSON; [objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON]; [RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"application/json"]; [objectManager addRequestDescriptor:requestDescriptor]; ``` and using following mapping for my Task object ``` NSDictionary *taskObjectMapping = @{ @"listID" : @"listID", @"taskID" : @"taskID", @"taskName" : @"taskName", @"taskCompletionStatus" : @"taskCompletionStatus", @"taskSyncStatus" : @"taskSyncStatus" }; RKEntityMapping *taskEntityMapping = [RKEntityMapping mappingForEntityForName:@"Task" inManagedObjectStore:managedObjectStore]; [taskEntityMapping addAttributeMappingsFromDictionary:taskObjectMapping]; taskEntityMapping.identificationAttributes = @[ @"taskID" ]; RKResponseDescriptor *taskResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:taskEntityMapping method:RKRequestMethodGET pathPattern:@"/api/list/:id" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]; [objectManager addResponseDescriptor:taskResponseDescriptor]; //Inverse mapping, to perform a POST RKRequestDescriptor *taskRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[taskEntityMapping inverseMapping] objectClass:[Task class] rootKeyPath:nil method:RKRequestMethodPOST]; objectManager.requestSerializationMIMEType = RKMIMETypeJSON; [objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON]; [RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"application/json"]; [objectManager addRequestDescriptor:taskRequestDescriptor]; //Inverse mapping, to perform a PUT taskRequestDescriptor = [RKRequestDescriptor requestDescriptorWithMapping:[taskEntityMapping inverseMapping] objectClass:[Task class] rootKeyPath:nil method:RKRequestMethodPUT]; objectManager.requestSerializationMIMEType = RKMIMETypeJSON; [objectManager setAcceptHeaderWithMIMEType:RKMIMETypeJSON]; [RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:@"application/json"]; [objectManager addRequestDescriptor:taskRequestDescriptor]; ``` Now my question is how to add relationship mapping between these two entites ? What would be proper way ? If i use i use following line of code ``` [taskEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"list.listID" toKeyPath:@"listID" withMapping:listEntityMapping]]; ``` a runtime error occurs saying "Unable to add mapping for keyPath listID, one already exists" and if i use this ``` [listEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"listID" toKeyPath:@"list.listID" withMapping:taskEntityMapping]]; ``` app crashes with this error the entity List is not key value coding-compliant for the key "list".' and if i omit the above code and try to get listID from relationship ``` task.list.listID ``` it gives me "0". Can anyone tell me what exactly am i doing wrong or what should i do to accomplish above task. I can give more details on this if needed. EDIT but my request to all list returns following json ``` GET www.mydomain.com/api/lists [ {"listID":"42","listName":"List 4","listSyncStatus":"1"}, {"listID":"41","listName":"List 3","listSyncStatus":"1"}, {"listID":"40","listName":"List 2","listSyncStatus":"1"} ] ``` and request to single list will return its task as follows ``` GET www.mydomain.com/api/list/42 [ {"taskID":"22","listID":"42","taskName":"Task 2","taskSyncStatus":"1","taskCompletionStatus":"1"}, {"taskID":"21","listID":"42","taskName":"Task 1","taskSyncStatus":"1","taskCompletionStatus":"1"} ] ``` i.e there is no cascading relationship in returned in json. is this wrong way or what am i missing here ? Corrected After Accepting Answer It turns out i was returning wrong json i.e. the returned json has no relationship in it while the iOS model has a relationship "tasks" so i edited my rest api to return correct nested json which is like below ``` [ { "listID" : "96", "listName" : "List 1", "listSyncStatus" : "1", "tasks" : [ { "taskCompletionStatus" : "1", "taskID" : "67", "taskName" : "Task 2", "taskSyncStatus" : "1" }, { "taskCompletionStatus" : "1", "taskID" : "66", "taskName" : "Task 1", "taskSyncStatus" : "1" } ] }, { "listID" : "97", "listName" : "List 2", "listSyncStatus" : "1", "tasks" : [ { "taskCompletionStatus" : "1", "taskID" : "69", "taskName" : "Task 1", "taskSyncStatus" : "1" }, { "taskCompletionStatus" : "1", "taskID" : "68", "taskName" : "Task 1", "taskSyncStatus" : "1" } ] } ] ``` after returning above nested json, everything works like charm, specially this line ``` [listEntityMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"tasks" toKeyPath:@"tasks" withMapping:taskEntityMapping]]; ``` Hope this helps grasping relationship concepts for people like me out there.