2012-10-24 44 views
4

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

的JSON的用户是一样的东西

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

和JSON的群体是一样的东西

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

我也有相应的核心数据对象,UserGroup,有一个组与用户之间的多对一关系映射。 Group中的关系属性被称为members,单独的NSArray被称为memberIDs包含所有成员用户的字符串ID数组。

我想在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显然会错代码,它似乎与我在上面的代码中创建的虚假用户映射有关(它是空的,因为没有要在ID数组中映射的东西)。

我试过的替代品,例如,当我添加了关键路径映射:

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

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

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正试图在ID字符串本身的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) {}]; 

以防万一这可以帮助其他人在类似的情况。我采取的方法可能仍然存在一些问题,但如此之好(甚至可以处理乱序加载,这很好) - 如果对我的原始问题有答案,仍然乐于听到任何人的声音。

回答

2

找到了一种方法来完成这项工作,也意识到我的问题中更新的方法只能用于嵌套对象,而不是引用对象。此线程让我在正确的轨道上:https://groups.google.com/forum/#!msg/restkit/swB1Akv2lTE/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) {}]; 

当我试过这种方法早些时候,该conf下的东西用于我的是这条线

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

其中第一键路径指的是用于被引用的对象的关键路径映射(users在这种情况下),没有被映射到的group对象内的关系的关键路径(在这种情况下将会是members)。

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

+0

嘿!我正在尝试做同样的事情,但我想知道,CoreData中的memberIDS类型是什么?我会尽快尝试!谢谢! – abisson

+0

@abisson检查Blake Watters的这个答案:https://groups.google.com/d/msg/restkit/9MG0CPi1aS0/olQGaSiJQjAJ – vitaminwater