How to avoid getting duplicate Core Data objects using local JSON?

404 views
Skip to first unread message

Evan Roth

unread,
Jun 17, 2013, 9:53:09 AM6/17/13
to res...@googlegroups.com
I'm running into an issue where I'm getting duplicate writes to my SQLite database every time I perform another mapping operation after the first one in RestKit 0.20.2.  I've looked online pretty extensively and can't seem to find a duplicate issue to what I'm experiencing—all of the similar problems I've seen center around using RestKit for everything, while I'm using RestKit just for the mapping and database operations, as I'm doing the network aspect in another library (STTwitter).

I have a unique `identificationAttribute` property set (the tweet ID) and am using a `managedObjectCache` initialized with `RKInMemoryManagedObjectCache`; however, every time I perform a mapping operation, I'm getting duplicates across the board on everything.  The library I'm using for the network side (STTwitter) returns the JSON as an array, so I iterate through each object in the array.  Is there some other operation I'm supposed to be performing? I was under the impression that RestKit compares the `identificationAttribute` property specified in mapped objects to what's already in the SQLite database before doing any insertions, but this doesn't appear to be happening.  I wasn't encountering this issue when I used it for everything in another project, using `RKManagedObjectRequestOperation`.

Here's how I set up the model:

    -(void)setup
    {
    self.objectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:[self managedObjectModel]];
    
    [self.objectStore createPersistentStoreCoordinator];
    
    NSString *path = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"FoodTruckxxx.sqlite"];
    NSLog(@"Setting up store at %@", path);
    [self.objectStore addSQLitePersistentStoreAtPath:path
                              fromSeedDatabaseAtPath:nil
                                   withConfiguration:nil
                                             options:self.optionsForSQLiteStore
                                               error:nil];
    
    [self.objectStore createManagedObjectContexts];
    
    self.objectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:self.objectStore.persistentStoreManagedObjectContext];
    }
and here's how I perform the mapping operation:

    -(void)performMapping
    {
    int i = 0;
    while (i < self.localCopyOfAllStatuses.count)
    {
        RKManagedObjectStore *store = [[FoodTruckDataModel sharedDataModel] objectStore];
        RKEntityMapping *mapping = [ObjectMappings FoodTruckArticleMapping];
        NSEntityDescription *entity = [NSEntityDescription entityForName:@"FoodTruck" inManagedObjectContext:store.persistentStoreManagedObjectContext];
        NSManagedObject *newManagedObject = [[NSManagedObject alloc] initWithEntity:entity insertIntoManagedObjectContext:store.persistentStoreManagedObjectContext];
        RKManagedObjectMappingOperationDataSource *mappingDS = [[RKManagedObjectMappingOperationDataSource alloc] initWithManagedObjectContext:store.persistentStoreManagedObjectContext cache:store.managedObjectCache];
        
        //assign new array to contain to just one object at a time and iterate through it
        NSArray *justOneStatus = [self.localCopyOfAllStatuses objectAtIndex:i];
        RKMappingOperation *operation = [[RKMappingOperation alloc] initWithSourceObject:justOneStatus destinationObject:newManagedObject mapping:mapping];
        operation.dataSource = mappingDS;
        NSError *error = nil;
        [operation performMapping:&error];
        [store.persistentStoreManagedObjectContext save:&error];
        [store.persistentStoreManagedObjectContext saveToPersistentStore:&error];
        i++;
    }
    }

And here is the mapping:

    +(RKEntityMapping *)FoodTruckArticleMapping
    {
    RKEntityMapping *jsonMapping = [RKEntityMapping mappingForEntityForName:@"FoodTruck" inManagedObjectStore:[[FoodTruckDataModel sharedDataModel] objectStore]];
    jsonMapping.identificationAttributes = @[@"tweetID"];
    
    [jsonMapping addAttributeMappingsFromDictionary:@{
     @"text": @"tweet", @"user.screen_name": @"foodTruckName", @"created_at": @"timeStamp", @"id": @"tweetID"}];
    
    return jsonMapping;
    }

And here is a complete operation from my log.  I also have this on stackoverflow, where someone suggested using a `RKManagedObjectResponseMapperOperation`, but that requires a URL and a URL response.  Any help would be greatly appreciated!

Blake Watters

unread,
Jun 17, 2013, 10:45:07 AM6/17/13
to res...@googlegroups.com
Eliminate the creation and assignment of the `newManagedObject` to the operation. RestKit will not perform existing object identification if you supply an object that is the target of the mapping operation.

You may also want to replace the use of `RKMappingOperation` with an instance of `RKMapperOperation`. This will take care of iterating your array of dictionaries for you, emitting `RKMappingOperation` instances for each, etc. With an `RKMapperOperation` you supply a dictionary specifying the keyPath to object mappings that is to be used. In this case it appears that you would want to do `@{ [NSNull null]: [ObjectMappings FoodTruckArticleMapping] }`


--
You received this message because you are subscribed to the Google Groups "RestKit" group.
To unsubscribe from this group and stop receiving emails from it, send an email to restkit+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Evan Roth

unread,
Jun 18, 2013, 12:09:21 AM6/18/13
to res...@googlegroups.com
Blake,

Thanks so much! I ended up going with your suggestion of using `RKMapperOperation,` which worked like a charm and indeed saved me the trouble of iterating through my array of JSON objects.  If you send me an email address for you, I'd like to PayPal you some money for a beer—it's the least I can do!

Evan

Blake Watters

unread,
Jun 18, 2013, 9:57:21 AM6/18/13
to res...@googlegroups.com
Bring it on! blakew...@gmail.com
Reply all
Reply to author
Forward
0 new messages