RestKit 发布嵌套的托管对象会创建重复项

Posted

技术标签:

【中文标题】RestKit 发布嵌套的托管对象会创建重复项【英文标题】:RestKit POSTing Nested Managed Objects Creates Duplicates 【发布时间】:2014-04-11 17:04:30 【问题描述】:

我在使用 RestKit 发布带有嵌套 NSManagedObjects 的 NSManagedObject 时遇到了一些困难。当 POST 返回时,我似乎得到了插入 CoreData 的子 NSManagedObjects 的重复记录。这是模型的快照:

这是我发布的 JSON:


  "actions": [], 
  "application": "Identify", 
  "createBy": "welcomed", 
  "createDt": "2014-04-11T16:26:15Z", 
  "description": null, 
  "externalId": null, 
  "groupId": "5", 
  "id": 0, 
  "images": [
    
      "format": "JPEG", 
      "height": 200, 
      "id": 0, 
      "image": "/9j/4A..../Pv5n/9k=", 
      "status": "C", 
      "type": "MUGSHOT", 
      "width": 200
    
  ], 
  "locked": null, 
  "modifyBy": null, 
  "modifyDt": null, 
  "priv": null

这是 POST 后从服务返回的 JSON:


"actions": [], 
  "application": "Identify", 
  "createBy": "welcomed", 
  "createDt": 1397233575000, 
  "description": null, 
  "externalId": null, 
  "groupId": "5", 
  "id": 11, 
  "images": [
    
      "captureDevice": null, 
      "createBy": null, 
      "createDt": null, 
      "format": "JPEG", 
      "height": 200, 
      "id": 11, 
      "image": "/9j/4AAQSkZJR.../Pv5n/9k=", 
      "recordId": 11, 
      "status": "C", 
      "type": "MUGSHOT", 
      "width": 200
    
  ], 
  "locked": false, 
  "modifyBy": null, 
  "modifyDt": null, 
  "priv": false

编辑(我想这很重要):这是 WTSImage 和 WTSRecord 的映射:

RKEntityMapping *recordMapping = [RKEntityMapping mappingForEntityForName:@"WTSRecord" inManagedObjectStore:self.managedObjectStore];
    [recordMapping addAttributeMappingsFromDictionary:@
                                                        @"id":@"dbId",
                                                        @"externalId":@"extId",
                                                        @"groupId":@"groupId",
                                                        @"application": @"application",
                                                        @"description": @"desc",
                                                        @"priv": @"priv",
                                                        @"locked": @"locked",
                                                        @"createBy": @"createBy",
                                                        @"createDt": @"createDt",
                                                        @"modifyBy": @"modifyBy",
                                                        @"modifyDt": @"modifyDt",
                                                        ];
    recordMapping.identificationAttributes = @[@"dbId"];

    //image mapping
    RKEntityMapping *imageMapping = [RKEntityMapping mappingForEntityForName:@"WTSImage" inManagedObjectStore:self.managedObjectStore];
    [imageMapping addAttributeMappingsFromDictionary:@
                                                       @"id": @"dbId",
                                                       @"status": @"status",
                                                       @"type": @"type",
                                                       @"format": @"format",
                                                       @"width": @"width",
                                                       @"height": @"height",
                                                       @"image": @"base64Image"
                                                       ];

    imageMapping.identificationAttributes = @[@"dbId"];
    [recordMapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:@"images" toKeyPath:@"images" withMapping:imageMapping]];

以下代码是我创建 NSManagedObjects 并调用 [RKObjectManager postObject:path:parameters:success:failure: 的地方:

WTSRecord *record = [NSEntityDescription insertNewObjectForEntityForName:@"WTSRecord" inManagedObjectContext:self.managedObjectContext];
record.createBy = @"welcomed";
record.createDt = [NSDate date];
record.application = kWTSApplicationIdentify;
record.groupId = @"5";

WTSImage *image = [NSEntityDescription insertNewObjectForEntityForName:@"WTSImage" inManagedObjectContext:self.managedObjectContext];
image.height = [NSNumber numberWithFloat:mugshot.size.height];
image.width = [NSNumber numberWithFloat:mugshot.size.width];
image.imageData = UIImageJPEGRepresentation(imageData, 1.0);
image.type = kWTSCaptureTypeMugshot;
image.format = kWTSCaptureFormatJpeg;
image.status = kWTSCaptureStatusCaptured;

image.record = record;
[record addImagesObject:image];

RKObjectManager *manager = [RKObjectManager sharedManager];
[manager postObject:record path:@"records" parameters:nil success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 

     failure:^(RKObjectRequestOperation *operation, NSError *error) 
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error Sending Record" message:error.localizedDescription delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alert show];
    ];

当调用成功块时,我检查 sqlite 数据库并插入了 1 个 WTSRecord 和 2 WTSImages。其中一个 WTSImage 具有 WTSRecord 的正确 FK 和数据库中的 PK,而另一个似乎是孤立的(未设置 dbId 和 WTSRecord 的 FK)。

这里是 RestKit 和 Core Data 跟踪日志的链接:https://dl.dropboxusercontent.com/u/466390/restkit2.txt

希望有人可以提供帮助!谢谢!

EDIT经过一番搜索,我找到了这个页面:https://github.com/RestKit/RestKit/issues/1228

在将 UUID 发布到 REST 服务之前,我是否必须在客户端使用 UUID 创建标识元素?如果不先在客户端设置标识属性,RestKit 是否无法将请求对象映射回对象存储中已创建的对象?

【问题讨论】:

【参考方案1】:

对于发布的对象,RestKit 了解如何使用响应数据更新该项目,但这不适用于关系内容。从技术上讲,它可以被编码,但目前还不是。

如果您需要映射后关系中的对象与您创建的对象相同,那么您就有问题了。如果您不介意它是一个不同的对象,那么问题只是删除重复项......

重复删除:

在处理 POST 响应时不使用获取请求块,因此您需要获取副本并手动将其删除。我将假设任何与记录具有 nil 关系的图像都是骗子,因此执行起来相对简单。

【讨论】:

我使用过的大多数允许创建图像容器的 API 都需要先创建容器,然后再进行多次上传(每个图像一个)。从网络管理的角度来看,这通常会更好,并且可以解决您的问题,因为每个发布的对象都会按照您的预期进行更新。 感谢 Wain 提供的信息!老实说,您是 RestKit 之神,过去几天您的回答为我节省了很多时间!与使用客户端生成的 UUID(我发现它能够更新嵌套的托管对象)相比,我更喜欢您的解决方案。我宁愿不处理数据库中额外的唯一标识符,所以我认为清理任何具有 nil 关系的图像是要走的路。感谢您确认 RestKit 的限制,以便我可以继续实际做一些工作。 :) 嗨@Wain,现在还是这样吗?我需要发送一堆已经存在于数据库中的相关对象,如果它们被映射,我希望它们与主对象相同,从而避免重复。非常感谢!

以上是关于RestKit 发布嵌套的托管对象会创建重复项的主要内容,如果未能解决你的问题,请参考以下文章

当响应包含在数组中时,RestKit POSTed 托管对象变得重复

在 RestKit 0.20.2 中创建的重复核心数据对象

如何使用 RestKit 将嵌套的 JSON 对象存储到核心数据中

markdown 还原备份文件会创建许多重复项。

RestKit RKObjectManager:getObjectsAtPath - 自定义处理

在字典中创建嵌套列表,列表中没有重复项