RestKit / CoreData:两次请求相同的URL时插入重复的对象而不是合并

Posted

技术标签:

【中文标题】RestKit / CoreData:两次请求相同的URL时插入重复的对象而不是合并【英文标题】:RestKit / CoreData: Duplicate objects inserted instead of merged when requesting the same URL twice 【发布时间】:2014-04-09 19:06:13 【问题描述】:

我的应用程序使用 RestKit 从 URL 获取,其有效负载包含 JSON 格式的对象(医院)列表。我第一次点击 URL 时,一切正常 - 有效负载被正确转换为一组 Hospital 托管对象,并将它们插入到持久存储中(通过执行获取请求并将结果与​​有效负载进行比较来验证)。

如果我从同一个 URL 再次执行 GET,返回相同的有效负载,RestKit 会将另一组 Hospital 对象(与第一组相同)插入到持久存储中。我希望 RestKit 确定第二组 Hospital 对象与第一组相同,然后在必要时更新第一组对象。

有效负载包含一个名为provider_number 的唯一标识符。

我在Hospital 模型中添加了一个provider_number 字段并勾选了Indexed

我相应地在RKEntityMapping 上设置了标识属性:

+ (RKEntityMapping *) hospitalMapping 
    RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:@"Hospital" inManagedObjectStore:[RKManagedObjectStore defaultStore]];
    [mapping setIdentificationAttributes:@[ @"provider_number"]];
    [mapping addAttributeMappingsFromDictionary:[self hospitalAttributeDictionary]];
    return mapping;

根据http://restkit.org/api/latest/Classes/RKManagedObjectRequestOperation.html#overview,我使用持久 MOC 在RKManagedObjectStore 上创建了托管对象缓存:

managedObjectStore.managedObjectCache = [[RKInMemoryManagedObjectCache alloc] initWithManagedObjectContext:managedObjectStore.persistentStoreManagedObjectContext];

RKObjectManager 配置为使用持久 MOC:

RKManagedObjectStore *managedObjectStore = [RKManagedObjectStore defaultStore];
NSManagedObjectContext *managedObjectContext = [managedObjectStore persistentStoreManagedObjectContext];

RKObjectManager *objectManager = [RKObjectManager managerWithBaseURL:url];
objectManager.managedObjectStore = managedObjectStore;

RKObjectManager 进一步配置了响应描述符和请求的响应 MIME 类型。

然后将映射操作排入队列:

[objectManager getObjectsAtPath:@""  
                     parameters:nil
                        success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) 
                           NSError *executeError = nil;
                           if([managedObjectContext saveToPersistentStore:&executeError]) 
                              NSLog(@"Saved hospitals to persistent store.");
                           
                           else 
                              NSLog(@"Failed to save to data store");
                           
                         failure:^(RKObjectRequestOperation *operation, NSError *error) 

                           UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"An Error Has Occurred" message:[error localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
                           [alertView show];
                        ];

执行两次会导致持久存储中的重复对象。我错过了什么?

【问题讨论】:

您是否看到数据存储中设置的provider_number(当您记录新的托管对象实例时)? 附注您无需在成功块中调用saveToPersistentStore: - 到那时它已经保存... 嗨@Wain,感谢您的回复。是的,provider_number 已正确映射:RKMapperOperation.m:403 Finished performing object mapping. Results: "" = ( "<Hospital: 0xa537e10> (entity: Hospital; id: 0xa52b500 <x-coredata:///Hospital/t296C047A-2D63-4AF4-9DDF-F5C422D3A10B15> ; data: \n \"provider_number\" = 450056;\n)", ); 感谢您的提示,我将删除对 saveToPersistentStore 的无关调用。 您是否对同一实体有另一个映射,但 identificationAttributes 设置为不同的值? 【参考方案1】:

来自此日志:

restkit.core_data:RKFetchRequestManagedObjectCache.m:124 找到对象'( )' using fetchRequest' (entity: Hospital; predicate: (provider_number == nil); sortDescriptors: ((null)); type: NSManagedObjectResultType; )'

Restkit 正在寻找现有项目,但谓词错误:predicate: (provider_number == nil)

目前还不清楚为什么。在managedObjectsWithEntity:attributeValues:inManagedObjectContext: 开头的RKFetchRequestManagedObjectCache.m 中放置一个断点,并检查备份堆栈以了解创建attributeValues 的内容以及provider_number 未正确完成的原因。

【讨论】:

确实如此。我想知道为什么它是零?我的猜测是 RK 正在构建涉及 provider_number 的谓词,因为我添加了 provider_number 作为实体标识属性,但如果我理解正确,看起来 RK 并没有用 @ 的值填充比较的另一边987654328@ 为 RK 刚刚创建的对象。我将设置断点并深入研究它... 想通了。 RKTransformedValueWithClass() 返回 nil,因为它无法将实体的标识属性解析为类型(它是可转换的)。我将属性的类型更改为 NSString *,现在识别工作正常。谢谢!

以上是关于RestKit / CoreData:两次请求相同的URL时插入重复的对象而不是合并的主要内容,如果未能解决你的问题,请参考以下文章

RestKit + CoreData,理解 RKManagedObjectRequestOperation

CoreData 和 RestKit

如何将 PUT 请求添加到 RestKit + Core Data?

CoreData+RESTKit:来自 NSFetchedResultsController 的同一对象的多个副本

RestKit + CoreData:操作成功时替换实体内容,失败时保持原样

iOS:RESTKit 与 CoreData 同步数据