RestKit:为外键关系创建存根

Posted

技术标签:

【中文标题】RestKit:为外键关系创建存根【英文标题】:RestKit: Creating stubs for foreign key relationships 【发布时间】:2014-07-11 15:46:32 【问题描述】:

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

具体来说,我使用Loopback 来生成带有TeamUser 等实体的API。默认情况下有两个 Endpoints 返回以下 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 routes、Foreign key relationship mapping with RestKit、Restkit: GET remote linked object when foreign key refers to missing local object in Core Data)之后,我还是无法弄清楚如何将整个对象图加载到核心中数据。

如果它使事情变得更容易,我当然也可以更改 API。出于显而易见的原因,我不想在每个 User 中嵌入整个 Team 对象,而是使用外键。另外,我想保持端点分开,主要是因为这是 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 属性建立关系。该映射适用于包含 TeamUser 对象作为数组的 JSON 有效负载(在响应描述符中使用 keyPath 而不是 pathPattern),但由于我相互独立调用的单独端点而失败。在这种情况下,连接关系所引用的对象可能尚未创建。因此,为了解决这个问题,应该创建一个 存根对象,并在这种情况下只填充 id 属性。

如何使用 RestKit 映射来实现这一点?


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


编辑 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 确实实际上只使用添加到对象管理器的最后一个响应描述符,这些描述符与给定路径匹配并且具有相同的键路径,正如所讨论的 @ 987654325@。感谢下面的答案,使用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】:

我认为我的以下答案以前有效,但也许我总是在 cmets 中偷偷摸摸关于响应描述符的完全匹配的问题。

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


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

【讨论】:

感谢@Wain,这听起来像是一个很好的解决方案,但似乎没有执行映射(请参阅上面的编辑 2)。 代码看起来没问题。如果您注释掉另一个映射并且它的工作原理看起来很奇怪。您可以在相同的路径模式和关键路径上匹配多个响应描述符没有问题。 hm 我又试了一次:我只请求用户 JSON 有效负载并注释掉除与“用户”路径模式匹配的两个映射之外的所有映射,teamStubMapping 和 userMapping。仅执行 userMapping。当我也将其注释掉时,将使用 teamStubMapping。您对如何调试有什么建议吗? 现在我尝试颠倒将响应描述符添加到对象管理器的顺序,发现它总是最后添加的那个正在执行。 这里github.com/RestKit/RestKit/issues/1719 第二个帖子实际上描述了这种行为的原因。有任何想法吗? ;)

以上是关于RestKit:为外键关系创建存根的主要内容,如果未能解决你的问题,请参考以下文章

Restkit 在嵌套的外键关系中使用 @parent

Restkit:当外键设置为 null 时,Core Data 中的关系不会重置

在没有外键的情况下连接与 RestKit 的关系

RestKit 对象映射与外键和服务

Restkit:当外键引用Core Data中缺少的本地对象时获取远程链接对象

在使用 CoreData 的 RestKit 的 mappingResult 中包含 foreignKeys 关系