使用Restkit从JSON数组映射关系

时间:2022-10-24 15:12:37

I will try to be as descriptive as possible with this issue...

我将尽量用描述性的语言来描述这个问题。

Scenario

场景

Let's say i have a NSManagedObject 'User'

假设我有一个NSManagedObject 'User'

@class Premise;

@interface User : NSManagedObject

@property (nonatomic, retain) NSNumber * identifier;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSSet *premises;
@end

@interface User (CoreDataGeneratedAccessors)

- (void)addPremisesObject:(Premise *)value;
- (void)removePremisesObject:(Premise *)value;
- (void)addPremises:(NSSet *)values;
- (void)removePremises:(NSSet *)values;

@end

And i also have a NSManagedObject 'Premise'

我还有NSManagedObject "前提"

@class User;

@interface Premise : NSManagedObject

@property (nonatomic, retain) NSNumber * identifier;
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) User *user;

@end

Based on it, i am creating a relationship route to map a JSON array of 'Premise' to the 'premises' attribute on the 'User' object.

基于此,我创建了一个关系路由,将“前提”的JSON数组映射到“用户”对象的“前提”属性。

Here's the route:

路线:

 let getPremisesRoute = RKRoute(relationshipName: "premises", 
                                objectClass: User.self, 
                                pathPattern: "user/:identifier/premises", 
                                method: .GET)

Here's the JSON response (/user/1/premises):

这里是JSON响应(/user/1/premises):

[
    {
        "id": 35,
        "name": "Icaraí"
    },
    {
        "id": 32,
        "name": "Remanso"
    }
]

Here's the response descriptor:

这是响应描述符:

  let getPremisesResponseDescriptor = RKResponseDescriptor(mapping: premiseMapping, method: .GET, pathPattern: "user/:identifier/premises", keyPath: nil, statusCodes: RKStatusCodeIndexSetForClass(.Successful))

And here are the respective mappings of 'User' and 'Premise'

这是用户和前提的映射

let userMapping = RKEntityMapping(forEntityForName: "User", inManagedObjectStore: moc)
userMapping.addAttributeMappingsFromDictionary(["id":"identifier", "name":"name"])      
userMapping.identificationAttributes = ["identifier"]
userMapping.addPropertyMapping(RKRelationshipMapping(fromKeyPath: nil, toKeyPath: "premises", withMapping: premiseMapping))


let premiseMapping = RKEntityMapping(forEntityForName: "Premise", inManagedObjectStore: moc)
premiseMapping.addAttributeMappingsFromDictionary(["id":"identifier", "name":"name"])
premiseMapping.identificationAttributes = ["identifier"]

Now to my problem

现在我的问题

Apparently, Restkit is getting a little bit confused during the mapping process. Here's the database after the request:

显然,在映射过程中,Restkit有点混乱。以下是请求后的数据库:

User Table: 使用Restkit从JSON数组映射关系

用户表:

Premise Table:

前提下表:

使用Restkit从JSON数组映射关系

Note the the relationship is not being created between the entities.

注意,实体之间没有创建关系。

Now, if I change the response descriptor's mapping from premise to user mapping, the database changes to this:

现在,如果我将响应描述符的映射从前提更改为用户映射,那么数据库将更改为:

Users Table:

用户表:

使用Restkit从JSON数组映射关系

Premise Table:

前提下表:

使用Restkit从JSON数组映射关系

I'm really confused on what's going on and I've tried a lot of solutions with no success.

我对发生了什么感到很困惑,我尝试了很多解决方案,但都没有成功。

Is the JSON response out of pattern or am I doing something wrong? The JSON response seems to be on a common pattern, with a nil key path.

JSON响应没有模式,还是我做错了什么?JSON响应似乎处于一个通用模式,具有nil键路径。

2 个解决方案

#1


1  

You're approaching the mapping incorrectly, or at least your mappings are wrong for what you're doing. Consider that the response is a user, but only the premises for a user, instead of considering it as a simple list of premises as you are now. Then you map to a user and insert the premises. Something like:

你对映射的处理是错误的,或者至少你的映射是错误的。考虑响应是一个用户,但只是用户的前提,而不是像现在这样把它看作一个简单的前提列表。然后映射到用户并插入前提。喜欢的东西:

RKResponseDescriptor(mapping: userMapping, method: .GET, pathPattern: "user/:identifier/premises", keyPath: nil, statusCodes: RKStatusCodeIndexSetForClass(.Successful))

And here are the respective mappings of 'User' and 'Premise'

这是用户和前提的映射

let userMapping = RKEntityMapping(forEntityForName: "User", inManagedObjectStore: moc)
userMapping.addAttributeMappingsFromDictionary(["@metadata.routing.parameters.idEntities":"identifier"])      
userMapping.identificationAttributes = ["identifier"]
userMapping.addPropertyMapping(RKRelationshipMapping(fromKeyPath: nil, toKeyPath: "premises", withMapping: premiseMapping))


let premiseMapping = RKEntityMapping(forEntityForName: "Premise", inManagedObjectStore: moc)
premiseMapping.addAttributeMappingsFromDictionary(["id":"identifier", "name":"name"])
premiseMapping.identificationAttributes = ["identifier"]

You don't have a user name in the response so you can't map it, and the user id is actually in the request so you need to use metadata to extract it.

响应中没有用户名,因此无法映射它,而用户id实际上位于请求中,因此需要使用元数据来提取它。

#2


1  

Ok, I found a possible solution based on @Wain's solution using foreign keys.

好的,我找到了一个基于@Wain使用外键的解决方案。

I added a new property 'userID' to the 'Premise' entity and mapped it to the identifier on the URL using metadata

我向“前提”实体添加了一个新属性“userID”,并使用元数据将其映射到URL的标识符。

let premiseMapping = RKEntityMapping(forEntityForName: "Premise", inManagedObjectStore: moc)

 premiseMapping.addAttributeMappingsFromDictionary(["id":"identifier", "name":"name", "@metadata.routing.parameters.identifier":"userID"])

Then I added a relationship connection to the 'premiseMapping'

然后我添加了一段关系到“前错”

premiseMapping.addConnectionForRelationship("user", connectedBy: ["userID":"identifier"])

If anyone has a more elegant solution please share with us.

如果有人有更优雅的解决方案,请与我们分享。

#1


1  

You're approaching the mapping incorrectly, or at least your mappings are wrong for what you're doing. Consider that the response is a user, but only the premises for a user, instead of considering it as a simple list of premises as you are now. Then you map to a user and insert the premises. Something like:

你对映射的处理是错误的,或者至少你的映射是错误的。考虑响应是一个用户,但只是用户的前提,而不是像现在这样把它看作一个简单的前提列表。然后映射到用户并插入前提。喜欢的东西:

RKResponseDescriptor(mapping: userMapping, method: .GET, pathPattern: "user/:identifier/premises", keyPath: nil, statusCodes: RKStatusCodeIndexSetForClass(.Successful))

And here are the respective mappings of 'User' and 'Premise'

这是用户和前提的映射

let userMapping = RKEntityMapping(forEntityForName: "User", inManagedObjectStore: moc)
userMapping.addAttributeMappingsFromDictionary(["@metadata.routing.parameters.idEntities":"identifier"])      
userMapping.identificationAttributes = ["identifier"]
userMapping.addPropertyMapping(RKRelationshipMapping(fromKeyPath: nil, toKeyPath: "premises", withMapping: premiseMapping))


let premiseMapping = RKEntityMapping(forEntityForName: "Premise", inManagedObjectStore: moc)
premiseMapping.addAttributeMappingsFromDictionary(["id":"identifier", "name":"name"])
premiseMapping.identificationAttributes = ["identifier"]

You don't have a user name in the response so you can't map it, and the user id is actually in the request so you need to use metadata to extract it.

响应中没有用户名,因此无法映射它,而用户id实际上位于请求中,因此需要使用元数据来提取它。

#2


1  

Ok, I found a possible solution based on @Wain's solution using foreign keys.

好的,我找到了一个基于@Wain使用外键的解决方案。

I added a new property 'userID' to the 'Premise' entity and mapped it to the identifier on the URL using metadata

我向“前提”实体添加了一个新属性“userID”,并使用元数据将其映射到URL的标识符。

let premiseMapping = RKEntityMapping(forEntityForName: "Premise", inManagedObjectStore: moc)

 premiseMapping.addAttributeMappingsFromDictionary(["id":"identifier", "name":"name", "@metadata.routing.parameters.identifier":"userID"])

Then I added a relationship connection to the 'premiseMapping'

然后我添加了一段关系到“前错”

premiseMapping.addConnectionForRelationship("user", connectedBy: ["userID":"identifier"])

If anyone has a more elegant solution please share with us.

如果有人有更优雅的解决方案,请与我们分享。