RestKit:为外键关系创建存根 [英] RestKit: Creating stubs for foreign key relationships

查看:272
本文介绍了RestKit:为外键关系创建存根的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难映射我的JSON API返回的外键关系与RestKit。



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



/ Teams /



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



/ Users /



  
{
name:Alice,
id:1,
teamId:1,
},
{
name:Bob,
id:2,
teamId:1,
},...
] code>

现在这是一个非常简单的API,对吧?它应该很容易与RestKit映射,但即使在阅读所有其他关于主题的问题(例如为浅路由寻求最佳RestKit / CoreData映射和JSON结构的建议使用RestKit的外键关系映射)我只是可以'在外部键引用到丢失的本地对象/ 19251748#19251748> RestKit: t找出如何将整个对象图加载到核心数据中。



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



所以我试图调用两个端点



团队映射



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



用户映射



  RKEntityMapping * userMapping = [RKEntityMapping mappingForEntityForName:@UserinManagedObjectStore:objectManager.managedObjectStore]; 
[userMapping addAttributeMappingsFromArray:@ [@name,@id,@teamId]];
userMapping.identificationAttributes = @ [@id];
[userMapping addConnectionForRelationship:@teamconnectedBy:@ {@teamId:@id}];
[objectManager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:userMapping method:RKRequestMethodGET pathPattern:@UserskeyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

正如其他问题(像上面链接的那样),我使用 RKConnectionDescription 通过瞬态 teamId 属性建立关系。该映射适用于包含 Team 对象作为数组的JSON有效内容(使用keyPath而不是pathPattern在响应描述符中),但是失败,我独立地彼此调用的单独的端点。在这种情况下,连接关系引用的对象可能尚未创建。因此,为了解决这个问题,应该创建一个 Stub对象,只有那种情况下填充的 id 属性。



如何通过RestKit映射实现这一点?






strong> Edit:如果我将teamId:1 的JSON结构更改为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:@UserskeyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

我打开跟踪日志记录,我没有看到这个映射执行,虽然,我做错了吗?是否跳过这个映射,因为有另一个已经匹配相同的模式?当我注释掉 User

所以RestKit 实际上只使用添加到匹配给定路径并具有相等关键路径的对象管理器的最后一个响应描述符,如
here on GitHub 。感谢以下答案,使用 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:@UserskeyPath:@teamIdstatusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)]];

我认为我以下的答案以前工作,但也许我总是偷偷摸摸



因此,创建另一个映射,但使它成为一个 nil keypath mapping 并在 @teamId的响应描述符上使用keypath 。这将使RestKit从响应中提取一个团队ID数组,并将它们作为对象项处理,并分隔到用户对象。






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


I am struggling to map the foreign key relationships returned by my JSON API with RestKit.

Specifically, I use Loopback to generate an API with Entities like Team and User. There are two Endpoints by default that return the following JSON:

/Teams/

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

/Users/

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

Now this is a pretty simple API, right? It should be easy to map with RestKit, but even after reading all those other questions about the topic (e.g. 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) I just can't figure out how to load the entire object graph into core data.

If it makes things easier, I can alter the API as well, of course. For obvious reasons, I don't want to embed the entire Team object in every User but use a foreign key instead. Also, I want to keep the Endpoints separate, mostly because this is the way Loopback generates the API by default.

So what I tried is calling both Endpoints (in an order that should not matter) with the following mapping:

Team Mapping

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 Mapping

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)]];

As suggested in other questions (like the ones linked above), I use an RKConnectionDescription to establish the relationship via a transient teamId property. The mapping works fine with a JSON payload that includes both Team and User objects as arrays (with a keyPath instead of a pathPattern in the response descriptor), but fails with separate Endpoints that I call independantly from each other. In that case, the object the connection relationship refers to may not have been created yet. So to solve this, a Stub Object should be created with only the id property populated in that situation.

How can I achieve this with a RestKit mapping?


Edit: Would it help if I changed the JSON structure from "teamId": 1 to "team": { "id": 1 } and add another response descriptor with the keyPath team? Not sure if that's easy to do with Loopback. What's the best way to do this?


Edit 2: So I added the following stub mapping:

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)]];

When I turn on trace logging, I don't see this mapping executed, though. What am I doing wrong? Is this mapping skipped because there is another one already matching the same pattern? When I comment out the User mapping, it does its job.


Edit 3: So RestKit does actually use only the last response descriptor added to the object manager of those matching a given path and with equal key paths, as discussed here on GitHub. Thanks to the answer below, using a nil key path mapping solves the issue:

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)]];

解决方案

I thought my below answer previously worked, but maybe I always snuck around the issue in the comments about exact matches of response descriptors.

So, create another mapping, but make it a nil keypath mapping and use a keypath on the response descriptor of @"teamId". This will cause RestKit to extract an array of team ids from the response and process them as object items, separate to the user objects.


The JSON is fine. Just create a new response descriptor which uses a teamStubMapping, which is a new mapping like teamMapping but replacing id with teamId. The path pattern of this response descriptor should be @"Users".

这篇关于RestKit:为外键关系创建存根的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆