繁体   English   中英

提取请求返回旧数据

[英]Fetch request returns old data

NSManagedObjectContextObjectsDidChangeNotification执行提取请求时,我得到的结果已经过时。

例如,考虑包含文档的目录,这些文档可以使用布尔属性( softDeleted )进行逻辑删除。 提取请求应返回具有至少一个未删除文档的所有目录( directoriesWithDocuments )。

初始状态是具有单个已删除文档的单个目录。 directoriesWithDocuments返回一个空数组。

以下代码通过将softDeleted布尔值设置为NO来还原文档。

[_context.undoManager beginUndoGrouping];
[_context.undoManager setActionName:@"undelete"];
document.softDeleted = @(NO);
NSError *error;
BOOL success = [_context save:&error]; // This triggers the notification
[_context.undoManager endUndoGrouping];

保存触发NSManagedObjectContextObjectsDidChangeNotification 我期望directoriesWithDocuments返回目录,但是它仍然返回一个空数组。

- (void)objectsDidChangeNotification:(NSNotification*)notification
{
    NSArray *objects = [self directoriesWithDocuments]; // Still empty!
}

但是,如果我保存上下文后立即执行directoriesWithDocuments ,或者立即或在下一个运行循环中执行,它将按预期返回目录。

这是获取请求的代码:

- (NSArray*)directoriesWithDocuments
{
    NSPredicate *predicate = [NSPredicate predicateWithFormat:@"ANY documents.softDeleted == NO"];
    NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:@"Directory"];
    fetchRequest.predicate = predicate;
    fetchRequest.includesPendingChanges = YES; // Just in case
    NSError *error = nil;
    NSArray *objects = [_context executeFetchRequest:fetchRequest error:&error];
    return directories;
}

我怀疑上下文具有某种类型的缓存,用于获取请求,直到处理通知后才会清除。 这是核心数据的预期表现吗? 还是我做错了什么?

解决方法

我目前正在像这样延迟获取请求的执行:

- (void)objectsDidChangeNotification:(NSNotification*)notification
{
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        // HACK: Give time to Core Data to process pending changes or invalidate caches
        NSArray *objects = [self directoriesWithDocuments]; // Returns the directory as expected
    }];

}

实验

根据@MikePollard的建议,我检查了NSManagedObjectContextWillSaveNotificationNSManagedObjectContextDidSaveNotificationdirectoriesWithDocuments的返回值。 结果是(按顺序):

  1. NSManagedObjectContextObjectsDidChangeNotification :空(错误)
  2. NSManagedObjectContextWillSaveNotification :空(错误)
  3. NSManagedObjectContextDidSaveNotification :1个目录(正确)

首先,看起来您在模型中定义了一个布尔属性,称为“ deleted”。

我记得这样做可能是一个重大问题,因为它与NSManagedObject isDeleted冲突(在KVC级别上)。 您可能想要更改它,以确保它不是罪魁祸首。

编辑

感谢回复。 我以删除为例。 这不是我正在使用的实际属性。 将其更改为softDeleted以免造成混淆

我在下面更新了我的建议,以使其与示例中的softDeleted相匹配。


就是说,我认为这里的工作归结为由includePendingChanges includesPendingChanges = YES构成“更改”的问题。

在上下文完成其保存之前,唯一的“更改”是对文档实体,而不是目录实体。

因此,当获取请求包含待定更改时,不存在任何待定更改的Directory实体,因此您将获得先前的结果。

为了验证该理论,请尝试一下:

[_context.undoManager beginUndoGrouping];
[_context.undoManager setActionName:@"delete"];
document.softDeleted = @(NO);
[document.directory willChangeValueForKey:@"documents"] // any attribute will do really
[document.directory didChangeValueForKey:@"documents"]
NSError *error;
BOOL success = [_context save:&error];
[_context.undoManager endUndoGrouping];

您对假的will / did changeValueForKey所做的工作是“弄脏”关联的Directory对象。 我的猜测是,它将被视为“已更改”,因此包括了获取结果。

令我惊讶的是,该谓词将被转换为SQL语句,因此在保存命中数据库之前,您将无法获得所需的结果...(不是那会导致您仅通过读取NSFetchRequest文档。)

因此,请尝试通过NSManagedObjectContextDidSaveNotification进行获取。

我敢打赌,如果您打开-com.apple.CoreData.SQLDebug 1,您将看到SQL语句。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM