PrimaryKeyAttribute does not work Restkit / Core Data

I just installed framework restkit 0.9.3 and followed the example of the Discussion Board. Well, everything just works fine, however, when I tried to use Core Data, my custom NSManagedObject class duplicates even after declaring it primaryKeyAttribute (userID). For example, when I send a login request to my web server, I return {"user":{"id":1, "username":"teste", ...}} .. but it seems to be creating a new a line every time it calls objectLoader: didLoadObjects.

User table:

enter image description here

Code example:

~ AppDelegate.m didFinishLaunching

 RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[User class]]; userMapping.primaryKeyAttribute = @"userID"; userMapping.setDefaultValueForMissingAttributes = YES; // clear out any missing attributes (token on logout) [userMapping mapKeyPathsToAttributes: @"id", @"userID", @"email", @"email", @"username", @"username", @"password", @"password", nil]; [objectManager.mappingProvider registerMapping:userMapping withRootKeyPath:@"user"]; 

~ User .m loginWithDelegate

 - (void)loginWithDelegate:(NSObject<UserAuthenticationDelegate>*)delegate { _delegate = delegate; [[RKObjectManager sharedManager] postObject:self delegate:self block:^(RKObjectLoader* loader) { loader.resourcePath = @"/login"; loader.serializationMapping = [RKObjectMapping serializationMappingWithBlock:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"username", @"password", nil]; }]; }]; } 

~ User .m didLoadObjects (RKObjectLoaderDelegate)

 - (void)objectLoader:(RKObjectLoader*)objectLoader didLoadObjects:(NSArray *)objects { if ([objectLoader wasSentToResourcePath:@"/login"]) { [self loginWasSuccessful]; } NSLog(@"number of user rows: %i", [User findAll].count); } 

What am I doing wrong?

+4
source share
3 answers

Do you execute RKManagedObjectCache correctly? For debugging, I just returned zero and forgot about it. After a while I found that I also have duplicates.

The cache works by retrieving local objects and comparing with objects returned by the server. Any local objects that are not in the server response will be deleted. In earlier versions, it used a fetch request, but in new versions you must manually execute the query and return the actual objects.

If you return zero, it considers that this object is not in your cache and will add a duplicate. Try to implement this method:

 + (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute value:(id)primaryKeyValue inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext 

For example:

 + (NSManagedObject *)findInstanceOfEntity:(NSEntityDescription *)entity withPrimaryKeyAttribute:(NSString *)primaryKeyAttribute value:(id)primaryKeyValue inManagedObjectContext:(NSManagedObjectContext *)managedObjectContext { NSFetchRequest* request = [[NSFetchRequest alloc] init]; [request setEntity: entity]; [request setFetchLimit: 1]; [request setPredicate:[NSPredicate predicateWithFormat:@"%K = %@", primaryKeyAttribute, primaryKeyValue]]; NSArray *results = [NSManagedObject executeFetchRequest:request inContext: managedObjectContext]; if ([results count] == 0) { return nil; } return [results objectAtIndex:0]; } 
+2
source

I found a problem related to targetObject (RKObjectLoader)

 /** * The target object to map results back onto. If nil, a new object instance * for the appropriate mapping will be created. If not nil, the results will * be used to update the targetObject attributes and relationships. */ 

So when I set it to nil , postObject calls findOrCreateInstanceOfEntity: withPrimaryKeyAttribute: andValue

 - (void)loginWithDelegate:(NSObject<UserAuthenticationDelegate>*)delegate { _delegate = delegate; [[RKObjectManager sharedManager] postObject:self delegate:self block:^(RKObjectLoader* loader) { loader.resourcePath = @"/login"; loader.targetObject = nil; loader.serializationMapping = [RKObjectMapping serializationMappingWithBlock:^(RKObjectMapping* mapping) { [mapping mapAttributes:@"username", @"password", nil]; }]; }]; } 
+2
source

Starting with the latest version of RESTKit (0.23.2), you can define the primary key as follows:

 [_mapping addAttributeMappingsFromDictionary:@{ @"id" : @"objectId", @"name" : @"name" }]; [_mapping setIdentificationAttributes:@[ @"objectId" ]]; 

Whereas objectId is the primary key for the main data object.

0
source