Reputation: 377
I have a problem with the object mapping from a JSON
string to a NSManagedObject
. I use RestKit
via getObject
request and the Core Data integration. And I want to automatically map the JSON response.
1.) I get from a webservice the following response ("A" object):
{
"Bs":[
{ "id" : "abc", "name" : "name 1"},
{ "id" : "def", "name" : "name 2"}
{ "id" : "abc", "name" : "name 1"},
],
"id": "1"
}
2.) This response has ordered values (B Objects), with sometimes the same object ("id" : "abc") more than one time. Further more, the order of the items is important.
3.)
Core-Data has not the support to save multiple relations to the same object, because it used a NSSet
(NSOrderedSet
). And it ignores all double objects.
Has anyone an idea how I could solve the problem?
My try, which fails:
1.) I insert a new core data table (AB), which:
2.)
I try to map the object with a RKValueTransformer
instance.
This iterates over the JSON
response for the B instances and create AB objects with the current position. These objects are saved in an NSSet
, which return from the custom value transformer
RKValueTransformer *aabbTransformer = [RKBlockValueTransformer valueTransformerWithValidationBlock:^BOOL(__unsafe_unretained Class sourceClass, __unsafe_unretained Class destinationClass) {
return ([sourceClass isSubclassOfClass:[NSArray class]] && [destinationClass isSubclassOfClass:[NSOrderedSet class]]);
} transformationBlock:^BOOL(id inputValue, __autoreleasing id *outputValue, Class outputValueClass, NSError *__autoreleasing *error) {
// Validate the input and output
RKValueTransformerTestInputValueIsKindOfClass(inputValue, [NSArray class], error);
RKValueTransformerTestOutputValueClassIsSubclassOfClass(outputValueClass, [NSOrderedSet class], error);
NSMutableOrderedSet *outputSet = [[NSMutableOrderedSet alloc] init];
NSInteger pos = 1;
for (id b in inputValue) {
// see JSON output at the top
// B instance already exists in core data persistent store
NSString *bid = [b valueForKeyPath:@"id"];
B *b = [B bById:bid];
// create AB instance
AB *ab = [NSEntityDescription ...]
ab.b = b;
ab.position = [NSNumber numberWithInteger:pos];
[outputSet addObject:ab];
pos++;
}
// return for A.abs
*outputValue = [[NSOrderedSet alloc] initWithOrderedSet:outputSet];
return YES;
}];
RKAttributeMapping *aabbMapping = [RKAttributeMapping attributeMappingFromKeyPath:@"bs" toKeyPath:@"abs"];
aabbMapping.valueTransformer = aabbMappingTransformer;
3.) But I get an error: illegal attempt to establish a relationship 'abs' between objects in different contexts But I use always the same context.
If you don't have an better idea, do you have a solution for this problem?
Upvotes: 0
Views: 408
Reputation: 119031
Your proposed model structure is a sensible solution for your duplicate data requirement. The only change you should make there is to ensure that all relationships are double ended (have an inverse) and have appropriate multiplicity. Be sure that the relationship from B
to AB
is to-many. The relationship from A
to AB
should also be to-many.
The general approach to this is to use multiple response descriptors:
A
object and AB
objects, key path is nil
B
objects without any duplication, key path is Bs
The response descriptor to create the A
object has a nested relationship mapping to create the AB
objects with duplicates and order - for this you can not use any identification attributes for AB
and you need to use the mapping metadata provided by RestKit.
Once the objects are created they then need to be connected and that would be done with a foreign key mapping. That means storing a transient attribute on the AB
instances which contains the id for the appropriate B
object and using that to make the connection.
Note that after updates you may have some orphaned objects (because you can't use identification attributes for AB
) in the data store as a result of this manipulation and you should consider creating a fetch request block to purge them out (or do this yourself periodically).
Upvotes: 0