RestKit 嵌套关系

Posted

技术标签:

【中文标题】RestKit 嵌套关系【英文标题】:RestKit nested relationships 【发布时间】:2014-04-14 00:45:47 【问题描述】:

使用 RestKit,我正在尝试映射以下 JSON。


  "userID": 1,
  "collections": [
    
      "collectionID": 120,
      "friends": [
        
          "friendID": 6,
          "orders": [
            
              "orderID": 1,
              "name": "Small"
            
          ]
        
      ]
    ,
    
      "collectionID": 123,
      "friends": [
        
          "friendID": 6,
          "orders": [
            
              "orderID": 2,
              "name": "Medium"
            
          ]
        
      ]
    
  ]

我正在使用 RestKit 和 MagicalRecord - 设置代码、映射和关系如下

NSURL *modelURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"]];
NSManagedObjectModel *managedObjectModel = [[[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL] mutableCopy];
RKManagedObjectStore *managedObjectStore = [[RKManagedObjectStore alloc] initWithManagedObjectModel:managedObjectModel];
NSString *storePath = [RKApplicationDataDirectory() stringByAppendingPathComponent:@"db.sqlite"];

[managedObjectStore addSQLitePersistentStoreAtPath:storePath fromSeedDatabaseAtPath:nil withConfiguration:nil options:nil error:nil];
[managedObjectStore createManagedObjectContexts];

// Configure MagicalRecord to use RestKit's Core Data stack
[NSPersistentStoreCoordinator MR_setDefaultStoreCoordinator:managedObjectStore.persistentStoreCoordinator];
[NSManagedObjectContext MR_setRootSavingContext:managedObjectStore.persistentStoreManagedObjectContext];
[NSManagedObjectContext MR_setDefaultContext:managedObjectStore.mainQueueManagedObjectContext];

RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:[NSURL URLWithString:@"http://127.0.0.1:3500"]];
objectManager.managedObjectStore = managedObjectStore;

RKEntityMapping *appMapping = [RKEntityMapping mappingForEntityForName:@"App" inManagedObjectStore:managedObjectStore];
appMapping.identificationAttributes = @[ @"userID" ];

RKEntityMapping *collectionMapping = [RKEntityMapping mappingForEntityForName:@"Collection" inManagedObjectStore:managedObjectStore];
collectionMapping.identificationAttributes = @[ @"collectionID" ];
[collectionMapping addAttributeMappingsFromArray:@[@"collectionID"]];

RKEntityMapping *friendMapping = [RKEntityMapping mappingForEntityForName:@"Friend" inManagedObjectStore:managedObjectStore];
friendMapping.identificationAttributes = @[ @"friendID" ];
[friendMapping addAttributeMappingsFromArray:@[@"friendID"]];

RKEntityMapping *orderMapping = [RKEntityMapping mappingForEntityForName:@"Order" inManagedObjectStore:managedObjectStore];
orderMapping.identificationAttributes = @[ @"orderID" ];
[orderMapping addAttributeMappingsFromArray:@[@"orderID", @"name"]];


RKRelationshipMapping *appCollectionRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"collections" toKeyPath:@"collections" withMapping:collectionMapping];
[appMapping addPropertyMapping:appCollectionRelationship];

RKRelationshipMapping *collectionFriendRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:friendMapping];
[collectionMapping addPropertyMapping:collectionFriendRelationship];

RKRelationshipMapping *friendsOrderRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"orders" toKeyPath:@"orders" withMapping:orderMapping];
[friendsOrderRelationship setAssignmentPolicy:RKUnionAssignmentPolicy];
[friendMapping addPropertyMapping:friendsOrderRelationship];

然后,使用下面的控制台查询我的 API 上的 /test 路由(输出上面的 JSON 块)...

RKResponseDescriptor *responseDescriptor = [RKResponseDescriptor responseDescriptorWithMapping:appMapping method:RKRequestMethodAny pathPattern:nil keyPath:nil statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[objectManager addResponseDescriptor:responseDescriptor];

[objectManager getObjectsAtPath:@"/test" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 

    App *app = [mappingResult firstObject];
    for (Collection *collection in app.collections) 
        NSLog(@"collectionID = %@", collection.collectionID);
        for (Friend *friend in collection.friends) 
            NSLog(@"friendID = %@", friend.friendID);
            for (Order *order in friend.orders) 
                NSLog(@"Name = %@", order.name);
            
        
    
 failure:^(RKObjectRequestOperation *operation, NSError *error) ];

提供以下输出 - 注意两个名称都是中型,而不是一个小而另一个中型。

collectionID = 120
friendID = 6
Name = Medium
Name = Small
collectionID = 123
friendID = 6
Name = Medium
Name = Small

为什么会发生这种情况?我猜这是因为两个好友 ID 相同,即使他们在不同的收藏夹下...

【问题讨论】:

【参考方案1】:

这是因为您有identificationAttributes = @[ @"friendID" ]; 和关系的默认关系连接规则而不是替换。所以,第二个映射找到第一个映射创建的好友,替换订单关系内容。

您实际上无法根据您显示的 JSON 更改唯一标识符,但您可能需要检查它(根据您的对象图要求)。

另外/或者,请参阅this answer,了解如何更改关系分配策略以不丢失原始关系内容的详细信息。

【讨论】:

感谢您的意见!所以我应该删除friendMapping.identificationAttributes并将当前关系代码更改为RKRelationshipMapping *collectionFriendRelationship = [RKRelationshipMapping relationshipMappingFromKeyPath:@"friends" toKeyPath:@"friends" withMapping:orderMapping]; [collectionFriendRelationship setAssignmentPolicy:RKUnionAssignmentPolicy];我什至不知道AssignmentPolicy! assignmentPolicy 自己改变可能就足够了,这取决于你想要模型中的什么对象,你认为什么是重复的...... 这是否意味着它将合并两个(可能更多)名称项目?查看编辑的代码(只是底部的关系) 是的,这就是为什么你需要决定你想要什么,union / 'duplicates' 嗯 - 任何一个选项都不是那么有用,因为我只需要一个 Name (在其他属性中 - 这只是一个简化的用例)。我想我可能会考虑从 Friend 对象中提取 Orders,并且只需有一个索引指向该 Friend 的相应 Order。除非我错过了什么?谢谢:)

以上是关于RestKit 嵌套关系的主要内容,如果未能解决你的问题,请参考以下文章

RestKit 0.20.1 复合键和嵌套关系

RestKit .22:无法成功映射与嵌套 JSON 的关系

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

RestKit 将未嵌套关系映射到拥有对象

RestKit - Nil 被映射到嵌套对象中以建立关系

RestKit嵌套的一对多关系映射很慢