Search code examples
iosimportrestkitforeign-key-relationship

RestKit importing JSON doesn't set relationships


As mentioned in the question header for some reason the relationships aren't set properly when I inspect the sqlite database.

I am importing two resources (books and chapters), each in one JSON file with a one-to-many structure. This is an example JSON:

books.json:      [ { "id": 1, "number": 12345, "name": "Book 1" } ]
chapters.json:   [ { "id": 1, "bookId": 1, "name": "Chapter 1" } ]

I've set the following mappings:

RKEntityMapping *bookMapping = [RKEntityMapping mappingForEntityForName:@"Book"
    inManagedObjectStore:managedObjectStore];
bookMapping.identificationAttributes = @[ @"id" ];
[bookMapping addAttributeMappingsFromArray:[Book attributesArray]]; // [@"id", @"number", @"name"]

RKEntityMapping *chapterMapping = [RKEntityMapping mappingForEntityForName:@"Chapter"
    inManagedObjectStore:managedObjectStore];
chapterMapping.identificationAttributes = @[ @"id" ];
[chapterMapping addAttributeMappingsFromArray:[Chapter attributesArray]]; // [@"id", @"bookId", @"name"]

And of course the connection:

[chapterMapping addConnectionForRelationship:@"book" connectedBy:@{ @"bookId": @"id" }];

Here is the part that imports the two JSON files:

RKManagedObjectImporter *importer = [[RKManagedObjectImporter alloc] initWithManagedObjectModel:managedObjectStore.managedObjectModel storePath:path];

NSString *bookJsonPath = [NSString stringWithFormat:@"%@/%@/books.json", [self getDocumentsPath], @"seeds"];
[importer importObjectsFromItemAtPath:bookJsonPath
                          withMapping:bookMapping
                              keyPath:nil
                                error:&error];

// [[importer managedObjectContext] saveToPersistentStore:&error];

NSString *chapterJsonPath = [NSString stringWithFormat:@"%@/%@/chapters.json", [self getDocumentsPath], @"seeds"];
[importer importObjectsFromItemAtPath:chapterJsonPath
                          withMapping:chapterMapping
                              keyPath:nil
                                error:&error];

success = [importer finishImporting:&error];

if (success) {
    [importer logSeedingInfo];

    NSLog(@"Finished seeding!");
}

The import process works perfectly fine, but the chapters have all NULL in the book foreign key column. The logs also show:

Caching instances of Entity 'Book' by attributes 'guid'
Imported 551 objects from file at path ... (books)
Caching instances of Entity 'Chapter' by attributes 'guid'
Imported 1908 objects from file at path ... (chapters)
Starting 1908 connection operations ...
A seed database has been generated 

which sort of indicates that it started to create connections but nothing happened.

 

Update 15.12.14: The two main errors were:

  1. That I used the reserved keyword id as a property (instead of say guid) and
  2. I had a stupid mistake in my foreign-key mapping! The foreign-key that came in the chapters json was book and my mapping expected bookId. Embarrassing! I changed the server to properly return bookId as the foreign-key and now it works.

This way only the connection was sufficient! No need to add RKRelationShipMappings.


Solution

  • You should create relationship between Book and Chapter, not just a connection.

    1. Chapter should have to many relation with Book object, like this enter image description here

    2. You should create Relationship Mapping between Chapter and Book, something like this:

      I didn't try to execute your code, but you have to create relationship mapping between Book and Chapter. Connection won't insert new record in Book table if book with ID 1 doesn't exists already.

    So, IMO you have to add something like this:

    RKEntityMapping* bookIDMapping = [RKEntityMapping mappingForEntityForName:@"Book"
                                                         inManagedObjectStore:managedObjectStore];
    
    bookIDMapping.identificationAttributes = @["bookId"];
    
    [chapterMapping addPropertyMapping:[RKRelationshipMapping 
                                        relationshipMappingFromKeyPath:@"bookId"
                             toKeyPath:@"bookId"
                           withMapping:bookIDMapping]];
    
    1. The last thing is about this line:

      chapterMapping.identificationAttributes = @[ @"id" ];

    If you called your property id, please rename it to bookId/chapterId. Id in Objective-C is a key word and it means that compiler will expect an object of any type here.

    Like I said, I didn't checked part of code I wrote here, but I think it'll help you. You'll understand the point :)