Question

I am having some difficulties POSTing an NSManagedObject with nested NSManagedObjects with RestKit. I appear to be getting duplicate records for the sub-NSManagedObjects inserted into CoreData when the POST returns. Here is a snapshot of the model:

Model

Here is the JSON that I am POSTing:

{
  "actions": [], 
  "application": "Identify", 
  "createBy": "welcomed", 
  "createDt": "2014-04-11T16:26:15Z", 
  "description": null, 
  "externalId": null, 
  "groupId": "5", 
  "id": 0, 
  "images": [
    {
      "format": "JPEG", 
      "height": 200, 
      "id": 0, 
      "image": "/9j/4A..../Pv5n/9k=", 
      "status": "C", 
      "type": "MUGSHOT", 
      "width": 200
    }
  ], 
  "locked": null, 
  "modifyBy": null, 
  "modifyDt": null, 
  "priv": null
}

Here is the JSON that is returned from the service after the POST:

{
"actions": [], 
  "application": "Identify", 
  "createBy": "welcomed", 
  "createDt": 1397233575000, 
  "description": null, 
  "externalId": null, 
  "groupId": "5", 
  "id": 11, 
  "images": [
    {
      "captureDevice": null, 
      "createBy": null, 
      "createDt": null, 
      "format": "JPEG", 
      "height": 200, 
      "id": 11, 
      "image": "/9j/4AAQSkZJR.../Pv5n/9k=", 
      "recordId": 11, 
      "status": "C", 
      "type": "MUGSHOT", 
      "width": 200
    }
  ], 
  "locked": false, 
  "modifyBy": null, 
  "modifyDt": null, 
  "priv": false
}

EDIT (I suppose this is important): Here is the mapping for the WTSImage and WTSRecord:

RKEntityMapping *recordMapping = [RKEntityMapping mappingForEntityForName:@"WTSRecord" inManagedObjectStore:self.managedObjectStore];
    [recordMapping addAttributeMappingsFromDictionary:@{
                                                        @"id":@"dbId",
                                                        @"externalId":@"extId",
                                                        @"groupId":@"groupId",
                                                        @"application": @"application",
                                                        @"description": @"desc",
                                                        @"priv": @"priv",
                                                        @"locked": @"locked",
                                                        @"createBy": @"createBy",
                                                        @"createDt": @"createDt",
                                                        @"modifyBy": @"modifyBy",
                                                        @"modifyDt": @"modifyDt",
                                                        }];
    recordMapping.identificationAttributes = @[@"dbId"];

    //image mapping
    RKEntityMapping *imageMapping = [RKEntityMapping mappingForEntityForName:@"WTSImage" inManagedObjectStore:self.managedObjectStore];
    [imageMapping addAttributeMappingsFromDictionary:@{
                                                       @"id": @"dbId",
                                                       @"status": @"status",
                                                       @"type": @"type",
                                                       @"format": @"format",
                                                       @"width": @"width",
                                                       @"height": @"height",
                                                       @"image": @"base64Image"
                                                       }];

    imageMapping.identificationAttributes = @[@"dbId"];
    [recordMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"images" toKeyPath:@"images" withMapping:imageMapping]];

The following code is where I create the NSManagedObjects and call [RKObjectManager postObject:path:parameters:success:failure::

WTSRecord *record = [NSEntityDescription insertNewObjectForEntityForName:@"WTSRecord" inManagedObjectContext:self.managedObjectContext];
record.createBy = @"welcomed";
record.createDt = [NSDate date];
record.application = kWTSApplicationIdentify;
record.groupId = @"5";

WTSImage *image = [NSEntityDescription insertNewObjectForEntityForName:@"WTSImage" inManagedObjectContext:self.managedObjectContext];
image.height = [NSNumber numberWithFloat:mugshot.size.height];
image.width = [NSNumber numberWithFloat:mugshot.size.width];
image.imageData = UIImageJPEGRepresentation(imageData, 1.0);
image.type = kWTSCaptureTypeMugshot;
image.format = kWTSCaptureFormatJpeg;
image.status = kWTSCaptureStatusCaptured;

image.record = record;
[record addImagesObject:image];

RKObjectManager *manager = [RKObjectManager sharedManager];
[manager postObject:record path:@"records" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {

    } failure:^(RKObjectRequestOperation *operation, NSError *error) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error Sending Record" message:error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
    }];

When the success block is invoked, I check the sqlite database and there is 1 WTSRecord inserted and 2 WTSImages. One of the WTSImages has the correct FK to the WTSRecord and the PK from the database, while the other one appears to be orphaned (dbId and the FK to WTSRecord are not set).

Here is a link to the RestKit and Core Data trace logs: https://dl.dropboxusercontent.com/u/466390/restkit2.txt

Hopefully someone can help! Thanks!

EDIT After some more searching, I found this page: https://github.com/RestKit/RestKit/issues/1228

Do I have to create identification elements on the client side using UUIDs before POSTing them to a REST service? Will RestKit not be able to map request objects back to objects that were already created in the object store without first setting an identification attribute on the client side?

Was it helpful?

Solution

For the posted object, RestKit understands how to update that item with the response data, but that doesn't apply to the relationship contents. Technically it could be coded, but it isn't currently.

If you need the object in the relationship after the mapping to be the same object that you create then you have an issue. If you don't mind it being a different object then the issue is just to delete the duplicate...

Duplicate deletion:

Fetch request blocks aren't used when processing a POST response so you'd need to fetch the dupe and delete it manually. I'm going to assume that any image with a nil relationship to a record is a dupe so it's a relatively simple fetch to execute.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top