restKit with certain JSON responses that don't match one-to-one with core data managed object

StackOverflow https://stackoverflow.com/questions/23241144

سؤال

Here is the setup: we have an API that provides data in JSON format, and want to use Restkit to map to two core data objects. The objects "products" and "resources", and they are related with a many-to-one relationship. 1 product can be related to many resources. Thus, we have the Product:

@class Resource; 
@interface Product : NSManagedObject

@property (nonatomic, retain) NSNumber * productid; 
@property (nonatomic, retain) NSString * descriptiontext; 
@property (nonatomic, retain) NSString * brand;
@property (nonatomic, retain) NSSet *productResource;    
@end

and the Resources

@class Product;
@interface Resource : NSManagedObject

@property (nonatomic, retain) NSNumber * productid;
@property (nonatomic, retain) NSNumber * resourceid;    
@property (nonatomic, retain) NSString * url;
@end

We have a problem with using Restkit for a situation where the API we are accessing provides its data in the following JSON format that doesn't correspond straightforwardly to the Core Data objects. Thus, for each product, the API is returning the related resources like this:

listproducts: [ 
   { productid: 2, 
     description: "description of product2", 
     brand: "brand 2", 
     resource: [ { resourceid: 22, url: "img_3786.jpg" }, 
                 { resourceid: 23, url: "tpa-plated-dessert.jpg" } ],
   }, 
   { productid: 3, 
     description: "description of product3", 
     brand: "brand 3", 
     resource: [ { resourceid: 15, url: "img_3786.jpg" } ],
   }, 
]

We know how to use Restkit to map correctly to the core data objects, IF the API provided the products and the resources separately. In that case, we can just use:

RKEntityMapping *productMapping = [RKEntityMapping mappingForEntityForName:@"Product" inManagedObjectStore:managedObjectStore];
productMapping.identificationAttributes = @[ @"productid" ];
[productMapping addAttributeMappingsFromDictionary:@{
                                                     @"productid"     : @"productid",
                                                     @"description"   : @"descriptiontext",
                                                     @"brand"         : @"brand"                            
                                                     }];

RKEntityMapping *resourceMapping = [RKEntityMapping mappingForEntityForName:@"Resource" inManagedObjectStore:managedObjectStore];
    resourceMapping.identificationAttributes = @[ @"resourceid" ];
    [resourceMapping addAttributeMappingsFromDictionary:@{
                                                          @"resourceid"     : @"resourceid",
                                                          @"productid"      : @"productid",
                                                          @"url"            : @"url",
                                                          }];

[productMapping addConnectionForRelationship:@"productResource" connectedBy:@"productid" ];

However, the API that we have is a nested one that has already done some of the "work" by providing the appropriate resources whose productid matches that of the product, so [productMapping addConnectionForRelationship:@"productResource" connectedBy:@"productid" ]; is not appropriate. Should we try something else, like

[productMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"listproducts.resource" toKeyPath:@"listproducts" withMapping:resourceMapping]];

? https://github.com/RestKit/RestKit/wiki/Object-mapping gives an example with nested JSON, but that is a different case. Here, the resources are nested and come without explicit productid, but take the productid from the parent .. how do we use Restkit with this API?

In other words, we want the NSSet productResource to be correctly populated, and corresponding Resource objects to be populated, but currently the NSSet is empty.

Here are the response descriptors:

RKResponseDescriptor *productRD = [RKResponseDescriptor responseDescriptorWithMapping:productMapping
                                                                               method:RKRequestMethodGET
                                                                          pathPattern:nil
                                                                              keyPath:@"listproducts"
                                                                          statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
RKResponseDescriptor *resourceRD = [RKResponseDescriptor responseDescriptorWithMapping:resourceMapping
                                                                               method:RKRequestMethodGET
                                                                          pathPattern:nil
                                                                              keyPath:@"resource"
                                                                          statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptorsFromArray:@[productRD, resourceRD]];
هل كانت مفيدة؟

المحلول

Should we try something else, like

[productMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"listproducts.resource" toKeyPath:@"listproducts" withMapping:resourceMapping]];

Yes, that is exactly what you should try. Except that you are already drilled into listproducts, so your from key path should just be resource. And the to key path is productResource based on your entity subclass.

Correct the above and the relationship will be populated. You only need explicit id storage when you are using foreign key mapping, not when the data is nested (because then the nesting describes the context for how to connect the relationship).

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top