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

标签 ios restkit

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

用户的 JSON 类似于

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

组的 JSON 类似于

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

我也有相应的核心数据对象,UserGroup,在组和用户之间具有一对多的关系映射。 Group 中的关系属性称为 members 和一个单独的 NSArray 称为 memberIDs 保存所有的字符串 ID 数组成员(member)用户。

我想在 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 试图将 memberIDs 数组中的 ID 字符串本身映射到 User 对象,这没有任何意义。我见过这样的例子,其中关系数组是一个字典列表,其中包含键(例如称为 id)和另一个对象的引用 ID,例如:

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

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

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

更新

我最终修改了 REST 接口(interface)以发送包含用户对象 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) {}];

以防万一这对处于类似情况的其他人有所帮助。我采用的方法可能仍然存在一些问题,但到目前为止一切顺利(它甚至可以处理乱序加载,这很好)- 如果我的原始问题有答案,我仍然很乐意听取任何人的意见。

最佳答案

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

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

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

还假设用户映射到键路径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];

其中第一个关键路径指的是被引用对象(在本例中为用户)的关键路径映射,而不是中关系的关键路径> 被映射的对象(在本例中是成员)。

通过此更改,所有关系都按预期工作,我很高兴。

关于ios - 通过 ID 数组在 RestKit 中映射关系不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13054112/

相关文章:

c# - 如何在 xamarin 上为 ios 创建自定义警报 View

ios - 我如何知道项目中的当前cocos2d版本?

ios - UITableViewCell 在滚动时显示错误的数据

ios - RestKit 核心数据映射连接与 URL 中的外键

iphone - RestKit 和核心数据整数数组

ios - 当用户触摸 TextView 时显示键盘时,我将如何向上插入 View ?

ios - 进入前台时应用程序崩溃

ios - NSDictionary 中的 boolean 值对于 x-www-form-urlencoded 序列化为 true/false

ios - RestKit 附加数据响应

ios - 特定实体的 RestKit 映射