Foreign key relationship mapping with RestKit - ios

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.

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.

Related

Unable to map nested array json with restkit

How can i map this json
{
"json": [{
"json_department": [{
"department": {
"id": 1,
"inst_id": 1,
"dept_name": "Department",
"description": "test"
},
"needDelete": true
}],
"json_subjects": [{
"subjects": [{
"id": 1,
"department_id": 1,
"subject_name": "Sub 1"
}, {
"id": 2,
"department_id": 1,
"subject_name": "Sub 2"
}],
"needDelete": true
}]
}]
}
#interface class_department : NSObject
#property(nonatomic, assign) NSInteger dept_id;
#property(nonatomic, assign) NSInteger inst_id;
#property(nonatomic, strong) NSString *dept_name;
#property(nonatomic, strong) NSString *description_;
#end
_
#interface class_department_list : NSObject
#property(nonatomic, strong) class_department *department;
#property(nonatomic, assign) BOOL needDelete;
#end
-
#interface sync_json : NSObject
#property(nonatomic, strong) NSMutableArray *json_department;
#property(nonatomic, strong) NSMutableArray *json_subjects;
#end
-
-(RKResponseDescriptor *)getResponseDescriptor
{
RKObjectMapping *class_department_mapping = [RKObjectMapping mappingForClass:[class_department class]];
[class_department_mapping addAttributeMappingsFromDictionary:#{
#"id":#"dept_id",
#"inst_id":#"inst_id",
#"dept_name":#"dept_name"
#"description":#"description_",
}];
RKObjectMapping *class_department_list_mapping = [RKObjectMapping mappingForClass:[class_department_list class]];
[class_department_list_mapping addAttributeMappingsFromDictionary:#{
#"needDelete":#"needDelete"
}];
[class_department_list_mapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"json_department.department"
toKeyPath:#"department"
withMapping:class_department_mapping]];
RKObjectMapping *json_mapping = [RKObjectMapping mappingForClass:[sync_json class]];
[json_mapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"json_department"
toKeyPath:#"json_department"
withMapping:class_department_list_mapping]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:json_mapping
method:RKRequestMethodGET
pathPattern:nil
keyPath:#"json"
statusCodes:statusCodes];
return responseDescriptor;
}
OKay this is code i'm using for mapping the json. i got the result for 'needDelete' but mapping to class_department is not happen. Please give me a way to done this.
Thank you.
Shinurag KR
Sorry, but try to forget this ugly implementation. Mantle do everythig pretty easy for you. Project: https://github.com/Mantle/Mantle Example: http://www.objc.at/mantle

RestKit using RKConnectionDescription to sideload data [duplicate]

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.
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.

iOS Restkit: how to parse nested path

I had a JSON response of this type:
{
"d": { "id": "1", "user": "test"}
}
which I was parsing with Restkit with the following code:
#interface ODataUser : NSObject<ODataObject>
#property (nonatomic, copy) NSString * id;
#property (nonatomic, copy) NSString * user;
-(NSString*)getId;
-(NSString*)getUser;
#end
RKObjectMapping *map = [RKObjectMapping mappingForClass:[ODataUser
class]]; [mapping addAttributeMappingsFromDictionary: #{ #"id" :
#"id", #"user" : #"user" } ];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:map method:RKRequestMethodGET pathPattern:nil keyPath:#"d" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
However, now my response has changed to something like this:
{
"d": { "results": [ {"id": "1", "user": "test"} ] }
}
How can I reflect those changes on the response on my code?
Change your response descriptor to use:
keyPath:#"d.results"
as this will navigate into the d dictionary to get the results array and process all of the dictionaries it contains.

RestKit mapping to a property only

I have a JSON response as follows:
{
response : {
data : {
subjects : [
{
},
{
}
]
}
}
}
and i have a NSManagedObject as follows:
#interface Department : NSManagedObject
#property (nonatomic, retain) NSNumber * id;
#property (nonatomic, retain) NSString * name;
#property (nonatomic, retain) NSSet *subjects;
#end
I have a department record in Department table with id = 1 and name = "Physics". I want to modify this existing department with obtained subjects from response JSON data. the subjects field only to be updated rest should be kept same. Would you please tell me the RestKit 0.20 mapping code for this?
UPDATE
this is the mapping i performed:
NSDictionary *subMappingDict = #{
#"id": #"id",
#"sub_name": #"name"
};
RKEntityMapping *subMapping = [RKEntityMapping mappingForEntityForName:#"Subject" inManagedObjectStore:managedObjectStore];
[subMapping addAttributeMappingsFromDictionary:subMappingDict];
subMapping.identificationAttributes = #[#"id"];
RKEntityMapping *deptMapping = [RKEntityMapping mappingForEntityForName:#"Department" inManagedObjectStore:managedObjectStore];
[deptMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"subjects" toKeyPath:#"subjects" withMapping:subMapping]];
RKEntityMapping *collegeMapping = [RKEntityMapping mappingForEntityForName:#"College" inManagedObjectStore:managedObjectStore];
[collegeMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"data" toKeyPath:#"department" withMapping:deptMapping]];
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:collegeMapping pathPattern:nil keyPath:#"response" statusCodes:statusCodes];
I have an existing College record which has an existing Department record. Here i want to update Department's subjects field only by the mapping.

RestKit 0.20: flattening the hierarchy with dynamic in JSON

I am using RestKit 0.20 and have a problem with mapping a JSON with hierarchy which contains dynamic keys into one Object.
The JSON looks like this:
{
"id": 42,
"name": "Name of this entity",
"specialDataMap": {
"2091:10": {
"id": 2091,
"type": "10",
"value": "1'509.49",
"name": "Name of special data type 10"
},
"2091:02" {
"id": 2091,
"type": "02",
"value": "5.5543",
"name": "Name of special data type 02"
}
}
}
and should be mapped with RestKit to such an object:
#interface InfoPoint : NSManagedObject
#property (nonatomic, retrain) NSString* identifier;
#property (nonatomic, retrain) NSString* name;
#property (nonatomic, retrain) NSString* valueOfType10;
#property (nonatomic, retrain) NSString* valueOfType02;
#end
As you can see, I do not want to create a relationship and store the special data into a separate object. It just doesn't make sense.
I want to assign the nested attributes into the InfoPoint object like all other attributes. Usually this would work with the key path of the nested objects but this path contains a dynamic part: "2091:10" is a combination of the id and the type where the id might change (was not my 'original' idea but I have to consume it).
I have read about the Handling Dynamic Nesting Attributes in the RestKit documentation. But I did not find if and how this might work together with nested attributes.
----- added as response to comment/question: ----
I have tried it as well with Dynamic Object Mapping. But it did not work because RestKit seems to have problem with the #"self" destination:
RKEntityMapping* type10Mapping = [RKEntityMapping mappingForEntityForName:#"InfoPoint" inManagedObjectStore:objectStore];
[type10Mapping addAttributeMappingsFromDictionary:#{
#"value": #"valueOfType10"}];
RKDynamicMapping* dynamicMapping = [[RKDynamicMapping alloc] init];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"specialDataMap" toKeyPath:#"self" withMapping:dynamicMapping]];
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
if ([[representation valueForKeyPath:#"type"] isEqualToString:#"10"]) {
return type10Mapping;
}
return nil;
}];
Your attempt at dynamic mapping isn't correct. You should supply the dynamic mapping to the response descriptor. The dynamic mapping should then create and return the appropriate mapping based on the keys it finds in the response. Something like (written free hand):
RKDynamicMapping* dynamicMapping = [[RKDynamicMapping alloc] init];
[dynamicMapping setObjectMappingForRepresentationBlock:^RKObjectMapping *(id representation) {
RKEntityMapping* typeMapping = [RKEntityMapping mappingForEntityForName:#"InfoPoint" inManagedObjectStore:objectStore];
[typeMapping addAttributeMappingsFromDictionary:#{
#"id" : #"identifier",
#"name": #"name",}];
NSDictionary *types = [representation valueForKeyPath:#"specialDataMap"];
for (NSString *key in types) {
NSDictionary *type = [[types objectForKey:key] objectForKey:#"type"];
if ([type isEqualToString:#"10"]) {
[typeMapping addAttributeMappingsFromDictionary:#{
[NSString stringWithFormat:#"specialDataMap.%#.value", key]: #"valueOfType10"}];
} else if ...
}
return typeMapping;
}];
RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:dynamicMapping
pathPattern:...
keyPath:nil
statusCodes:[NSIndexSet indexSetWithIndex:200]];

Resources