在RestKit中通过一个ID数组映射关系不起作用

我试图通过RestKit将用户和组映射到CoreData对象,维护两者之间的关系。

用户的JSON是类似的

{"users": [{"fullname": "John Doe", "_id": "1"} ... ] } 

和组的JSON是类似的

 {"groups": [{"name": "John's group", "_id": "a", "members": ["1", "2"] ... ] } 

我也有对应的核心数据对象, UserGroup ,在组和用户之间有一对多的关系映射。 组中的关系属性称为members而单独的名为memberIDs NSArray包含所有成员用户的stringID数组。

我想在RestKit中完成的是加载这些对象,并为我映射关系。 加载用户的代码是直接标准的东西,加载组的代码是类似的

 RKObjectManager* objectManager = [RKObjectManager sharedManager]; RKManagedObjectMapping* groupMapping = [RKManagedObjectMapping mappingForClass:[Group class] inManagedObjectStore:objectManager.objectStore]; groupMapping.primaryKeyAttribute = @"identifier"; [groupMapping mapKeyPath:@"_id" toAttribute:@"identifier"]; [groupMapping mapKeyPath:@"name" toAttribute:@"name"]; [groupMapping mapKeyPath:@"members" toAttribute:@"memberIDs"]; [objectManager.mappingProvider setMapping:groupMapping forKeyPath:@"groups"]; // Create an empty user mapping to handle the relationship mapping RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[User class] inManagedObjectStore:objectManager.objectStore]; [groupMapping hasMany:@"members" withMapping:userMapping]; [groupMapping connectRelationship:@"members" withObjectForPrimaryKeyAttribute:@"memberIDs"]; RKObjectRouter* router = objectManager.router; [router routeClass:[Group class] toResourcePath:@"/rest/groups/:identifier"]; [router routeClass:[Group class] toResourcePath:@"/rest/groups/" forMethod:RKRequestMethodPOST]; // Assume url is properly defined to point to the right path... [[RKObjectManager sharedManager] loadObjectsAtResourcePath:url usingBlock:^(RKObjectLoader *loader) {}]; 

当我运行这个代码的时候,我得到了下面的警告吐出了好几次(似乎每个关系大约有两次):

 2012-10-24 08:55:10.170 Test[35023:18503] W restkit.core_data.cache:RKEntityByAttributeCache.m:205 Unable to add object with nil value for attribute 'identifier': <User: 0x86f7fc0> (entity: User; id: 0x8652400 <x-coredata:///User/t01A9EDBD-A523-4806-AFC2-9B06873D764E531> ; data: { fullname = nil; identifier = nil; }) 

奇怪的是,关系得到了正确的设置(甚至看着sqlite数据库,一切看起来都很好),但我不满意RestKit代码中出现错误的东西,似乎有什么关系在上面的代码中创build的假用户映射(它是空的,因为没有什么可以在ID数组中映射)。

我已经尝试了替代品,例如当我添加一个关键path映射:

 [userMapping mapKeyPath:@"" toAttribute:@"identifier"]; 

它抱怨,显然是因为关键path是空的

 2012-10-24 09:24:11.735 Test[35399:14003] !! Uncaught exception !! [<__NSCFString 0xa57f460> valueForUndefinedKey:]: this class is not key value coding-compliant for the key . 

如果我尝试使用真正的User映射

 [groupMapping hasMany:@"members" withMapping:[[RKObjectManager sharedManager].mappingProvider objectMappingForKeyPath:@"users"]]; 

我得到以下错误

 2012-10-24 09:52:49.973 Test[35799:18403] !! Uncaught exception !! [<__NSCFString 0xa56e9a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _id. 2012-10-24 09:52:49.973 Test[35799:18403] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0xa56e9a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _id.' 

好像RestKit试图将IDstring本身在memberIDs数组中映射到User对象,这没有任何意义。 我已经看到关系数组是带有键的字典列表(例如,被称为id )的例子,其中引用ID指向另一个对象,例如:

 {"groups": [{"name": "John's group", "_id": "a", "members": [ {"_id": "1"}, {"_id": "2"} ] ... ] } 

但我不想改变我的JSON(除此之外,我希望RestKit足够灵活,以支持其他方式)。

有谁知道在RestKit中做这种关系映射的正确方法是什么?

更新

我最终修改了REST接口来发送一个包含用户对象ID的字典列表(就像上面的最后一个例子),并得到它的工作。 仍然不完全满意的设置,但代码现在看起来像

 RKObjectManager* objectManager = [RKObjectManager sharedManager]; RKManagedObjectMapping* groupMapping = [RKManagedObjectMapping mappingForClass:[Group class] inManagedObjectStore:objectManager.objectStore]; groupMapping.primaryKeyAttribute = @"identifier"; [groupMapping mapKeyPath:@"_id" toAttribute:@"identifier"]; [groupMapping mapKeyPath:@"name" toAttribute:@"name"]; [groupMapping mapKeyPath:@"members._id" toAttribute:@"memberIDs"]; [objectManager.mappingProvider setMapping:groupMapping forKeyPath:@"groups"]; // Create an empty user mapping to handle the relationship mapping RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[User class] inManagedObjectStore:objectManager.objectStore]; userMapping.primaryKeyAttribute = @"identifier"; [userMapping mapKeyPath:@"_id" toAttribute:@"identifier"]; [groupMapping hasMany:@"members" withMapping:userMapping]; [groupMapping connectRelationship:@"members" withObjectForPrimaryKeyAttribute:@"memberIDs"]; RKObjectRouter* router = objectManager.router; [router routeClass:[Group class] toResourcePath:@"/rest/groups/:identifier"]; [router routeClass:[Group class] toResourcePath:@"/rest/groups/" forMethod:RKRequestMethodPOST]; // Assume url is properly defined to point to the right path... [[RKObjectManager sharedManager] loadObjectsAtResourcePath:url usingBlock:^(RKObjectLoader *loader) {}]; 

以防万一,这有助于处于类似情况的其他人。 我采取的方法可能仍然存在一些问题,但是到目前为止还是如此(甚至处理乱序加载,这是很好的) – 如果对我原来的问题有答案,我还是会喜欢听到任何人的声音。

find了一个方法来使这个工作,也意识到我的问题更新的方法只能用于嵌套的对象,而不是引用的对象。 这个线程让我走上了正确的轨道: https ://groups.google.com/forum/#!msg/restkit/swB1Akv2lT​​E/mnP2OMSqElwJ(值得一读的是,如果你正在处理RestKit中的关系)

假设JSON组仍然看起来像原始的JSON:

 {"groups": [{"name": "John's group", "_id": "a", "members": ["1", "2"] ... ] } 

还假设用户被映射到一个keypath users (即像[objectManager.mappingProvider setMapping:userMapping forKeyPath:@"users"]; )映射关系的正确方法如下所示:

 RKObjectManager* objectManager = [RKObjectManager sharedManager]; RKManagedObjectMapping* groupMapping = [RKManagedObjectMapping mappingForClass:[Group class] inManagedObjectStore:objectManager.objectStore]; groupMapping.primaryKeyAttribute = @"identifier"; [groupMapping mapKeyPath:@"_id" toAttribute:@"identifier"]; [groupMapping mapKeyPath:@"name" toAttribute:@"name"]; [groupMapping mapKeyPath:@"members" toAttribute:@"memberIDs"]; [objectManager.mappingProvider setMapping:groupMapping forKeyPath:@"groups"]; [groupMapping mapKeyPath:@"users" toRelationship:@"members" withMapping:[[RKObjectManager sharedManager].mappingProvider objectMappingForKeyPath:@"users"] serialize:NO]; [groupMapping connectRelationship:@"members" withObjectForPrimaryKeyAttribute:@"memberIDs"]; RKObjectRouter* router = objectManager.router; [router routeClass:[Group class] toResourcePath:@"/rest/groups/:identifier"]; [router routeClass:[Group class] toResourcePath:@"/rest/groups/" forMethod:RKRequestMethodPOST]; // Assume url is properly defined to point to the right path... [[RKObjectManager sharedManager] loadObjectsAtResourcePath:url usingBlock:^(RKObjectLoader *loader) {}]; 

当我早些时候尝试过这种方法的时候,让我困惑的是这条线

 [groupMapping mapKeyPath:@"users" toRelationship:@"members" withMapping:[[RKObjectManager sharedManager].mappingProvider objectMappingForKeyPath:@"users"] serialize:NO]; 

其中第一个关键path指的是被引用的对象(在这种情况下是users )的关键path映射,而不是被映射的group对象(其在本例中是members )内的关系的关键path。

有了这个变化,所有的关系都按预期工作,我很高兴。