Reputation: 9658
Working with RestKit, I'm trying to map the following JSON.
{
"userID": 1,
"collections": [
{
"collectionID": 120,
"friends": [
{
"friendID": 6,
"orders": [
{
"orderID": 1,
"name": "Small"
}
]
}
]
},
{
"collectionID": 123,
"friends": [
{
"friendID": 6,
"orders": [
{
"orderID": 2,
"name": "Medium"
}
]
}
]
}
]
}
I'm utilising RestKit and MagicalRecord - setup code, mapping and relationships below
NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"]];
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"db.sqlite"];
[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:nil];
[managedObjectStore createManagedObjectContexts];
// Configure MagicalRecord to use RestKit's Core Data stack
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:managedObjectStore.persistentStoreCoordinator];
[NSManagedObjectContext MR_setRootSavingContext:managedObjectStore.persistentStoreManagedObjectContext];
[NSManagedObjectContext MR_setDefaultContext:managedObjectStore.mainQueueManagedObjectContext];
RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://127.0.0.1:3500"]];
objectManager.managedObjectStore = managedObjectStore;
RKEntityMapping *appMapping = [RKEntityMapping mappingForEntityForName:@"App" inManagedObjectStore:managedObjectStore];
appMapping.identificationAttributes = @[ @"userID" ];
RKEntityMapping *collectionMapping = [RKEntityMapping mappingForEntityForName:@"Collection" inManagedObjectStore:managedObjectStore];
collectionMapping.identificationAttributes = @[ @"collectionID" ];
[collectionMapping addAttributeMappingsFromArray:@[@"collectionID"]];
RKEntityMapping *friendMapping = [RKEntityMapping mappingForEntityForName:@"Friend" inManagedObjectStore:managedObjectStore];
friendMapping.identificationAttributes = @[ @"friendID" ];
[friendMapping addAttributeMappingsFromArray:@[@"friendID"]];
RKEntityMapping *orderMapping = [RKEntityMapping mappingForEntityForName:@"Order" inManagedObjectStore:managedObjectStore];
orderMapping.identificationAttributes = @[ @"orderID" ];
[orderMapping addAttributeMappingsFromArray:@[@"orderID", @"name"]];
RKRelationshipMapping *appCollectionRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"collections" toKeyPath:@"collections" withMapping:collectionMapping];
[appMapping addPropertyMapping:appCollectionRelationship];
RKRelationshipMapping *collectionFriendRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:friendMapping];
[collectionMapping addPropertyMapping:collectionFriendRelationship];
RKRelationshipMapping *friendsOrderRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"orders" toKeyPath:@"orders" withMapping:orderMapping];
[friendsOrderRelationship setAssignmentPolicy:RKUnionAssignmentPolicy];
[friendMapping addPropertyMapping:friendsOrderRelationship];
Then, querying the /test route on my API (which outputs the JSON block above) with the below console out...
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:appMapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];
[objectManager getObjectsAtPath:@"/test" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
App *app = [mappingResult firstObject];
for (Collection *collection in app.collections) {
NSLog(@"collectionID = %@", collection.collectionID);
for (Friend *friend in collection.friends) {
NSLog(@"friendID = %@", friend.friendID);
for (Order *order in friend.orders) {
NSLog(@"Name = %@", order.name);
}
}
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {}];
Provides the following output - notice both Name's are Medium, not one Small and the other Medium.
collectionID = 120
friendID = 6
Name = Medium
Name = Small
collectionID = 123
friendID = 6
Name = Medium
Name = Small
Why would this be happening? I'm going to guess that it's because both friend ID's are the same, even though they're under different collections...
Upvotes: 0
Views: 175
Reputation: 119031
This is because you have identificationAttributes = @[ @"friendID" ];
and the default relationship connection rule for relationships rather than replacement. So, the second mapping finds the friend created by the first mapping and replaces the order relationship contents.
You can't realistically change the unique identifier based on the JSON you show, but you might want to examine that (in relation to your object graph requirements).
Also / alternatively, see this answer for details of how to change the relationship assignment policy so that the original relationship contents aren't lost.
Upvotes: 1