批量更新后更新托管对象上下文中的托管对象

Posted

技术标签:

【中文标题】批量更新后更新托管对象上下文中的托管对象【英文标题】:Update Managed Objects in Managed Object Context After Batch Update 【发布时间】:2014-09-18 05:25:12 【问题描述】:

当您使用自 ios 8 起可用的 NSBatchUpdateRequest 类执行批量更新时,任何现有的托管对象上下文都不知道对持久存储所做的更改。我的问题是如何更新托管对象上下文以反映持久存储中的更改。

我正在使用获取的结果控制器,我尝试通过在托管对象上下文上调用 refreshObject:mergeChanges: 并重新加载表视图来将每个托管对象变成故障,但这似乎没有奏效。

【问题讨论】:

【参考方案1】:

NSBatchUpdateRequest 可以设置为具有NSStatusOnlyResultTypeNSUpdatedObjectIDsResultTypeNSUpdatedObjectsCountResultType 的结果类型。 NSUpdatedObjectIDsResultType 是唯一返回有关哪些对象受批处理操作影响的有意义信息的方法。

使用对象 ID,您可以通知上下文需要刷新这些对象。任何观察上下文的获取结果控制器都将看到更改通知并采取相应措施。

示例:如何解雇所有人。

[context performBlock:^
    NSError                 *batchError     = nil;
    NSBatchUpdateRequest    *batchRequest   = nil;
    NSBatchUpdateResult     *batchResult    = nil;

    batchRequest = [NSBatchUpdateRequest batchUpdateRequestWithEntityName:@"Employee"];
    [batchRequest setPropertiesToUpdate:@@"employed" : @NO];
    [batchRequest setPredicate:nil];
    [batchRequest setAffectedStores:[[context persistentStoreCoordinator] persistentStores] ];
    [batchRequest setResultType:NSUpdatedObjectIDsResultType];
    batchResult = (NSBatchUpdateResult *)[context executeRequest:batchRequest error:&batchError];

    if ([[batchResult result] respondsToSelector:@selector(count)])
        if ([[batchResult result] count] > 0)
            [context performBlock:^
                for (NSManagedObjectID *objectID in [batchResult result])
                    NSError         *faultError = nil;
                    NSManagedObject *object     = [context existingObjectWithID:objectID error:&faultError];
                    // Observers of this context will be notified to refresh this object.
                    // If it was deleted, well.... not so much.
                    [context refreshObject:object mergeChanges:YES];
                
            ];
         else 
            // We got back nothing!
        
     else 
        // We got back something other than a collection
    
];

显然,在很多情况下,这无法满足您的需求,或者根本不起作用。您可能必须刷新相当多的上下文 - 在上下文链上递归执行刷新块确实有效,但不会意识到任何同级上下文(这是避免创建同级的另一个原因)。

【讨论】:

我之前尝试过这种方法,但它对我不起作用。批量更新成功,但托管对象上下文不引入更改。您是否测试过您的解决方案? 我有。确保它是根上下文,并且所有对象都是故障 问题似乎是托管对象上下文使用缓存数据。我只有通过将托管对象上下文的stalnessInterval 属性设置为0.0 才能使其工作。这并不理想。有没有办法绕过托管对象上下文的缓存或删除它? 你好像误会了。您应该使用根上下文并确保所有对象都为故障。不是故障的对象是内存中的表示。如果上下文有一个对象的内存副本,它将使用它。如果它是子上下文,它将从其父上下文中拉出对象。故障对象。故障是 Core Data 中的一个基本概念。 我对故障很熟悉。然而,问题出在获取的结果控制器上。将托管对象变为故障后,需要在获取的结果控制器上调用performFetch:【参考方案2】:
- (NSBatchUpdateResult*)executeBatchUpdateRequest:(NSBatchUpdateRequest*)request
                                          context:(NSManagedObjectContext*)context
                                            error:(NSError**)error
    NSBatchUpdateResult *bur = (NSBatchUpdateResult *)[context executeRequest:request error:error];
    if (bur && bur.resultType == NSUpdatedObjectIDsResultType)
        NSArray <NSManagedObjectID*> *arr = bur.result;
        if ([arr isKindOfClass:NSArray.class] && arr.count > 0)
            // can update multiple contexts
            [NSManagedObjectContext mergeChangesFromRemoteContextSave:@NSUpdatedObjectsKey:arr
                                                         intoContexts:@[context]];
    
    return bur;

【讨论】:

以上是关于批量更新后更新托管对象上下文中的托管对象的主要内容,如果未能解决你的问题,请参考以下文章

选项卡栏应用程序更新实体中的共享托管对象上下文不会传播到其他选项卡

核心数据:父/子托管对象上下文是不是适合更新一组多个对象?

更新当前的 CoreData 条目

Core Data - 批量处理获取结果的属性

CoreData 和一对多关系的并发错误

CoreData 合并冲突显示托管对象版本更改而不是数据