RestKit:为外键关系创建存根

时间:2014-07-11 15:46:33

标签: ios core-data foreign-keys restkit restkit-0.20

我正在努力将我的JSON API返回的外键关系映射到RestKit。

具体来说,我使用Loopback生成包含TeamUser等实体的API。默认情况下,有两个端点返回以下JSON:

/小组/

[
  {
    "title": "Team Title",
    "id": 1,
  }
]

/用户/

[
  {
    "name": "Alice",
    "id": 1,
    "teamId": 1,
  },
  {
    "name": "Bob",
    "id": 2,
    "teamId": 1,
  }, ...
]

现在这是一个非常简单的API,对吗?使用RestKit进行映射应该很容易,但即使在阅读了有关该主题的所有其他问题后(例如Seeking recommendations for best RestKit/CoreData mapping and JSON structure for shallow routesForeign key relationship mapping with RestKitRestkit: GET remote linked object when foreign key refers to missing local object in Core Data),我也无法弄清楚如何将整个对象图加载到核心数据中。

如果它让事情变得更容易,我当然也可以改变API。出于显而易见的原因,我不想在每个Team中嵌入整个User对象,而是使用外键。此外,我希望将端点保持分离,主要是因为这是Loopback默认生成API的方式。

所以我尝试使用以下映射调用两个端点(按照无关紧要的顺序):

Team映射

RKEntityMapping *teamMapping = [RKEntityMapping mappingForEntityForName:@"Team" inManagedObjectStore:objectManager.managedObjectStore];
[teamMapping addAttributeMappingsFromArray:@[ @"title", @"id" ]];
teamMapping.identificationAttributes = @[ @"id" ];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:teamMapping method:RKRequestMethodAny pathPattern:@"Teams" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

User映射

RKEntityMapping *userMapping = [RKEntityMapping mappingForEntityForName:@"User" inManagedObjectStore:objectManager.managedObjectStore];
[userMapping addAttributeMappingsFromArray:@[ @"name", @"id", @"teamId" ]];
userMapping.identificationAttributes = @[ @"id" ];
[userMapping addConnectionForRelationship:@"team" connectedBy:@{ @"teamId": @"id" }];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:userMapping method:RKRequestMethodGET pathPattern:@"Users" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

正如其他问题(如上面链接的问题)所示,我使用RKConnectionDescription通过瞬态teamId属性建立关系。映射适用于JSON有效负载,包括TeamUser对象作为数组(在响应描述符中使用keyPath而不是pathPattern),但是由于我从每个端点独立调用单独的端点而失败其他。在这种情况下,可能尚未创建连接关系所引用的对象。因此,要解决此问题,应创建一个存根对象,并且在该情况下仅填充id属性。

如何使用RestKit映射实现此目的?


编辑:如果我将JSON结构从"teamId": 1更改为"team": { "id": 1 }并使用keyPath team添加另一个响应描述符,会有帮助吗?不确定Loopback是否容易做到这一点。 最好的方法是什么?


编辑2:所以我添加了以下存根映射:

RKEntityMapping *teamStubMapping = [RKEntityMapping mappingForEntityForName:@"Team inManagedObjectStore:objectManager.managedObjectStore];
[teamStubMapping addAttributeMappingsFromDictionary:@{@"teamId": @"id"}];
teamStubMapping.identificationAttributes = @[ @"id" ];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:teamStubMapping method:RKRequestMethodAny pathPattern:@"Users" keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

当我启用跟踪日志记录时,我不会看到此映射已执行。我究竟做错了什么?这个映射是否被跳过,因为还有另一个映射已匹配相同的模式?当我注释掉User映射时,它就能完成它的工作。


编辑3:所以RestKit 确实实际上只使用添加到匹配给定路径和相同密钥路径的对象管理器的最后一个响应描述符,如上所述{ {3}}。感谢下面的答案,使用nil密钥路径映射解决了问题:

RKEntityMapping *teamStubMapping = [RKEntityMapping mappingForEntityForName:@"Team inManagedObjectStore:objectManager.managedObjectStore];
[teamStubMapping addPropertyMapping:[RKAttributeMapping attributeMappingFromKeyPath:nil toKeyPath:@"id"]];
teamStubMapping.identificationAttributes = @[ @"id" ];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:teamStubMapping method:RKRequestMethodAny pathPattern:@"Users" keyPath:@"teamId" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

1 个答案:

答案 0 :(得分:2)

我认为我的下面的答案以前有效,但也许我总是在关于响应描述符的完全匹配的评论中躲过这个问题。

因此,创建另一个映射,但将其设为nil keypath mapping并在@"teamId"的响应描述符上使用密钥路径。这将导致RestKit从响应中提取团队ID数组,并将它们作为对象项处理,与用户对象分开。


JSON很好。只需创建一个使用teamStubMapping的新响应描述符,这是一个新的映射,如teamMapping,但将id替换为teamId。此响应描述符的路径模式应为@"Users"