【问题标题】:Core Data fetch predicate nil check failing/unexpected results?核心数据获取谓词零检查失败/意外结果?
【发布时间】:2015-09-13 23:12:59
【问题描述】:

我有一个包含数千个实体的核心数据层,不断与服务器同步。同步过程使用获取请求来检查 deleted_at 以进行软删除。在 performBlockAndWait 调用中有一个执行保存操作的上下文。关系映射由 RestKit 库处理。

CoreDataEntity 类是 NSManagedObject 的子类,也是我们所有不同核心数据对象类的超类。它具有我们所有实体都继承的一些属性,例如 deleted_at、entity_id 以及所有样板的 fetch 和 sync 方法。

我的问题是一些 fetch 请求在修改对象后似乎返回不一致的结果。例如删除一个对象后(将deleted_at设置为当前日期):

[CoreDataEntity fetchEntitiesWithPredicate:[NSPredicate predicateWithFormat:@"deleted_at==nil"]];

使用 deleted_at == [NSDate today] 返回结果

我已经通过另外循环遍历结果并删除设置了 deleted_at 的实体成功地解决了此问题,但是我无法解决相反的问题:

[CoreDataEntity fetchEntitiesWithPredicate:[NSPredicate predicateWithFormat:@"deleted_at!=nil"]];

在相同条件下返回一个空数组,阻止服务器同步成功。

我已确认已在对象上设置了 deleted_at,并且上下文保存成功。我只是不明白在哪里重置导致过时结果的缓存?

感谢您的帮助!

编辑:添加更多信息,似乎一旦这些对象之一损坏,使其注册的唯一方法是再次修改值。这可能是某种核心数据索引在修改值时没有更新吗?

更新:RestKit https://github.com/RestKit/RestKit/issues/2218 似乎有问题

【问题讨论】:

  • 你检查过你的上下文吗?确保在访问它们时保存在合并到主上下文的适当上下文中。您可能正在执行操作并且可能未正确同步您的上下文。使用上面提供的代码,考虑到它可能有很多东西,真的没有什么可做的。
  • 只有一个上下文。我将把它添加到问题中。谢谢!
  • 您可以将您的CoreDataEntity 的详细信息添加到您的帖子中吗?加上performBlockAndWait 代码。
  • 我不知道您是否在自己的时间里发现了这个问题,但我们肯定需要更多代码来确定所指出的问题。你能设置一个带有数据模型和核心数据堆栈的虚拟项目来复制这个问题吗?
  • 非常断断续续。我会尝试这样做。

标签: ios core-data restkit nspredicate nsfetchrequest


【解决方案1】:

您显然正在对 Core Data 使用一些语法糖扩展。我想在你的情况下它是一个 SheepData,对吧?

fetchEntitiesWithPredicate:那里实现如下:

+ (NSArray*)fetchEntitiesWithPredicate:(NSPredicate*)aPredicate
{
    return [self fetchEntitiesWithPredicate:aPredicate inContext:[SheepDataManager sharedInstance].managedObjectContext];
}

您确定[SheepDataManager sharedInstance].managedObjectContext 会收到您对对象所做的所有更改吗?它是接收保存通知,还是您的保存上下文的子上下文?

尝试用这个替换你的 fetch one-liner:

[<your saving context> performBlockAndWait:^{
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"CoreDataEntity"];
    request.predicate = [NSPredicate predicateWithFormat:@"deleted_at==nil"];

    NSArray *results = [<your saving context> executeFetchRequest:request error:NULL];
}];

【讨论】:

    【解决方案2】:

    首先,您是否在保存后查看商店以确保您的更改存在?如果不查看您的整个 Core Data 堆栈,就很难深入了解可能出了什么问题。如果您正在保存并且您在商店中看到更改,那么问题就会出现在您的上下文中。它们是如何建造的以及何时建造的。如果您正在处理可能导致您的问题的兄弟上下文。

    需要更多关于核心数据堆栈外观的详细信息。

    是的,变化就在那里。正如我在问题中提到的,我可以遍历我的结果并成功删除所有设置为 deleted_at 的结果

    那不是我的问题。查看内存中的对象和查看磁盘上的 SQLite 文件中的对象是有区别的。我对这种行为的疑问是:

    1. 在您再次查询之前,更改是否已保存到磁盘中
    2. 您是否在使用多个上下文并可能尝试从过时的同级中获取数据。

    因此我的问题是关于磁盘更改以及您的核心数据堆栈是什么样的。

    线程

    如果您使用一种上下文,您是否在应用程序中使用了多个线程?如果是这样,您是否在多个线程上使用该上下文?

    我可以看到一种情况,如果您违反线程限制规则,您可能会像这样损坏数据。

    【讨论】:

    • 是的,变化就在那里。正如我在问题中提到的,我可以遍历我的结果并成功删除所有设置了 deleted_at 的结果。
    • 啊,误会了。我会检查磁盘并告诉你。就多种情况而言……我相信我们只使用一种。我一直在尝试为每个保存操作创建一个新的上下文,看看是否可以缓解问题,但我还没有成功。
    • 添加更多上下文会混淆问题,除非您知道为什么要这样做,否则不要使用多个上下文。将它们扔在那里以“帮助”以及将线程添加到“帮助”。
    【解决方案3】:

    尝试添加一个额外的属性deleted,它是一个默认值为false 的布尔值。然后始终设置属性,您可以根据您目前的需要查找truefalse 的实体。如果值为true,那么您可以查看deleted_at 以了解何时。

    或者尝试将deleted_at 属性设置为某个旧日期(可能是 1980 年 1 月 1 日),那么任何未删除的内容都会有一个固定日期,该日期太旧而无法由用户设置。

    编辑:deleted_at 可能存在一些问题,从未接触过一些使系统混乱的实体。您也可能将获取请求设置为以字典样式返回结果,在这种情况下,最近的更改不会反映在获取结果中。

    【讨论】:

    • 我会尝试这个,谢谢。但是,我们在不同实体上遇到了类似的布尔收藏标记问题。我相信它们是相关的。如果这可行,我会报告。谢谢!
    • 回应您的编辑:什么会导致最近的更改没有具体反映?
    • 当获取请求设置为返回类型DictionaryResultType时,获取来自存储的磁盘版本而不是内存版本,这意味着它忽略了includesPendingChanges中的值(完整的讨论见developer.apple.com/library/prerelease/ios/documentation/Cocoa/…)根据我的经验,告诉上下文先保存并没有奏效。
    • 我们使用的是默认结果类型,并且我们没有包括待处理的更改...但包括待处理的更改并没有解决问题。
    猜你喜欢
    • 2023-03-18
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多