11

I'm totally new to RestKit and am struggling somewhat.

JSON:

{
    "teams": [
        {
            "id": 1,
            "name": "Team A"
        },
        {
            "id": 2,
            "name": "Team B"
        }
    ],
    "users": [
        {
            "id": 1,
            "name": "cameron",
            "teamId": 1
        },
        {
            "id": 2,
            "name": "paul",
            "teamId": 2
        }
    ]
}

CoreData:

@interface Team : NSManagedObject
@property (nonatomic, retain) NSNumber * teamId;
@property (nonatomic, retain) NSString * name;
@end




@interface User : NSManagedObject
@property (nonatomic, retain) NSNumber * userId;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) Team * team;
@end

My application logic looks like this:

// team mapping
RKEntityMapping *teamMapping = [RKEntityMapping mappingForEntityForName:@"Team" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
teamMapping.identificationAttributes = @[@"teamId"];
[teamMapping addAttributeMappingsFromDictionary:@{
 @"id": @"teamId",
 @"name": @"name"
 }];


// Register our mappings with the provider
RKResponseDescriptor *teamResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:teamMapping
                                                                                   pathPattern:nil
                                                                                       keyPath:@"teams"
                                                                                   statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.objectManager addResponseDescriptor:teamResponseDescriptor];



// user mapping
RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:@"User" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
userMapping.identificationAttributes = @[@"userId"];
[userMapping addAttributeMappingsFromDictionary:@{
 @"id": @"userId",
 @"name": @"name"
 }];


// Register our mappings with the provider
RKResponseDescriptor *userResponseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:userMapping
                                                                                   pathPattern:nil
                                                                                       keyPath:@"users"
                                                                                   statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.objectManager addResponseDescriptor:userResponseDescriptor];

I can't for the life of me work out how to get RestKit to populate the team Property of the user objects.

I've look at so many posts but nothing I try works, is this not a usual use case?

Does anyone know how to do this, help would be very appreciated!

Thanks.

Camsoft
  • 11,718
  • 19
  • 83
  • 120

1 Answers1

17

You need to add a transient attribute to your User entity which holds the associated teamId. This needs to be added to your userMapping.

Then, you need to add a relationship definition to your userMapping:

[userMapping addConnectionForRelationship:@"team" connectedBy:@{ @"teamId": @"teamId" }];

This gives RestKit the information it needs to make the connection and instructs it to make the connection as part of the mapping operation.

Wain
  • 118,658
  • 15
  • 128
  • 151
  • I am facing a very similar situation and I was wondering what will RestKit do when parsing a `User` and there is no existing `Team` with that user's `teamId`: Will it leave the relationship as nil? Will it create a new Team and fill it only with the teamId value? Is there any way of doing the latter? – veducm Feb 17 '14 at 19:15
  • @veducm to guarantee that stub objects are created you would likely need a second response descriptor which navigated the keypaths to the ids (because the first response descriptor needs to copy the ids to the other object). – Wain Feb 17 '14 at 19:46
  • Thanks! So I understand that the relationship would be left as `nil`. On the other hand, I did not get how to do this second response descriptor... do you know where I can see some sample code, read about it or find any hint on how this could be done? – veducm Feb 17 '14 at 20:22
  • No specific example. It's just a normal response descriptor, but being very selective with key path. The foreign key mapping is done after the basic mappings IIRC. Try creating the response descriptor and raise a question if you have issues. – Wain Feb 17 '14 at 22:30
  • @Wain I am doing this exact same thing, but every relationship specified by `addConnectionForRelationship:connectedBy:` ends up being `nil` when RESTkit attempts to persist it to Core Data. Why would this happen? – Matt Baker Apr 07 '14 at 11:57
  • @MattBaker, if you weren't mapping the values into the transient attributes then there would be no error and no connection made... – Wain Apr 07 '14 at 11:58
  • @Wain I have checked the tracing output, and in the JSON -> Entity step it reports that the foreign key values from the JSON into my Transient properties are successfully mapped. These transient properties are then referenced in my `addConnectionForRelationship:connectedBy:`. In fact, the error message RESTkit returns from Core Data has the transient foreign key property populated, but the resulting relationship entity is `nil`. – Matt Baker Apr 07 '14 at 12:06
  • @MattBaker, you will most likely need to raise a question and show your source JSON, mappings and error message (log output) – Wain Apr 07 '14 at 12:10
  • 1
    @Wain There were two issues: 1) I was missing response descriptors for several of my objects, and 2) I was mapping both sides of a many-to-many link object that RestKit didn't seem to like. Once I commented out the `addConnectionForRelationship:connectedBy:@{"arrayOfIds": "objectId"}` and just left the definition for the other side of the relationship it was happy. – Matt Baker Apr 07 '14 at 15:52
  • @Wain I am running into a similar problem and you can probably help me out ;) my json payload `/Users` just contains the `User` objects with their `teamID`. To get the corresponding `Team` objects, I would have to call `/Teams`. How can I load the object graph into core data? Establishing an `RKConnectionDescription` is not enough, obviously, because the `Team` objects do not exist in the database yet, they have to be fetched first.. – knl May 22 '14 at 20:36
  • @knl you can create multiple response descriptors to create stubs of the objects you don't have much info for. Create a new question if you have issues and show what you tried. – Wain May 22 '14 at 21:04
  • @Wain - I'm not sure how I would implement this in my example - http://stackoverflow.com/questions/24374488/restkit-using-rkconnectiondescription-to-sideload-data - I'm trying to implement a one-to-many relationship and I just cannot get it to work using the code in your answer. What am I doing wrong? – Wasim Jun 24 '14 at 19:38