【问题标题】:Is it possible to disable cascade delete for a specific Core Data save?是否可以为特定的核心数据保存禁用级联删除?
【发布时间】:2015-04-23 18:28:58
【问题描述】:

问题:

当您在 NSManagedObjectContext 上调用 save 时,当有 deletedObjects 需要处理时,它会进行大量工作来跟踪关系以确定哪些相关对象也需要删除。这是在每次保存时完成的(即使在父/子上下文的情况下),如果我知道我将通过这些父上下文保存,我希望能够在第一次之后跳过对每个上下文的此检查,但是我找不到这样做的机制。

背景:

这是情况,我有 3 个上下文:

  • C(B 的子上下文):用于工作的后台线程上下文
  • B(A 的子上下文):主线程上下文,用于我的 Fetch Result Controller,UI 访问
  • A(持久存储的子级):用于保存到磁盘的后台线程上下文

我的对象图是“丰富的”,其中一些关系针对具有 100,000 多个项目的表。正因为如此,删除速度很慢(级联删除删除每个根对象删除多个对象)......但是在分析性能时,我意识到它实际上比它需要的速度慢了很多,在保存过程中的大部分CPU / 时间用于解决图中的关系(尝试找出哪些相关对象也需要删除)......并且每次保存都会重复这个过程,即使我正在保存。
示例保存过程:

  • 上下文 C 有 1 个已删除对象
  • 保存上下文 C -> B(跟踪关系大约需要 1 秒的时间)
  • 现在已保存上下文 C(0 个已删除对象),上下文 B 具有原始已删除对象,以及 30 个新的相关对象也需要删除(31 个对象)
  • 保存上下文 B -> A(大约 1 秒的工作重新检查这些关系,这是我想跳过的工作)
  • 上下文 B 已保存(已删除 0 个对象),上下文 A 具有 B 必须删除的相同 31 个对象
  • 保存上下文 A -> 持久存储(这里的工作很轻松,似乎这一步不需要重新检查)

我尝试子类化并查看-[NSManagedObject validateForDeletion]-[NSManagedObjectContext processPendingChanges],但没有成功。有什么想法吗?

【问题讨论】:

  • 只是一个想法,可能完全错误。您是否尝试过清空您不想做任何工作的上下文,即reset。当然,只有当您不需要保存该特定上下文所产生的任何更改时,这才可以。

标签: ios objective-c core-data nsmanagedobjectcontext


【解决方案1】:

应该可以选择性地启用/禁用删除规则如果您使用多个 Core Data 堆栈并且如果您不介意编写一些中等复杂的代码。您最终会得到多个托管对象上下文,其中一些具有规则,而另一些则没有。交易是:

  • NSManagedObjectModel 在您首次加载时是可变的,因此您可以在代码中修改模型,只要您不进行使其与持久存储不兼容的更改(这将需要迁移)。李>
  • 模型兼容性仅由影响数据如何保存到持久存储的细节决定。 不包括删除规则,因此无需迁移即可对其进行修改。 (请参阅[NSRelationshipDescription versionHash] 的文档了解影响兼容性的因素。
  • NSManagedObjectModel 的实例仅在将它们与持久存储一起使用之前是可变的,因此您必须在加载任何数据之前进行更改。这意味着,如果您在某些情况下需要删除规则,但在其他情况下不需要,则需要 NSManagedObjectModel 的不同实例。

因此,如果您创建完全独立的 Core Data 堆栈(NSManagedObjectModelNSPersistentStoreCoordinator 等的独立实例),您可以将一个堆栈配置为没有这些删除规则,但将它们保留在其他堆栈上。由于删除规则不会影响模型哈希,它们仍然是兼容的。

您不能对父/子托管对象上下文执行此操作,因为根据定义,它们是同一个 Core Data 堆栈的一部分。

要删除或更改删除规则,您必须从您的 NSManagedObjectModel 实例开始。在模型中获取entities,然后为您感兴趣的实体获取relationshipsByName。最后,在NSRelationshipDescription 上,将deleteRule 更改为您想要的任何内容(在这种情况下可能是NullifyDeleteRule)。

这会有点复杂,但应该可以。

顺便说一句,我有兴趣了解有关您的性能分析结果的更多细节。

【讨论】:

  • 嗯...不确定这是否适用于我的场景,因为这里的目标是能够通过父/子上下文进行保存,而不会产生额外的关系查找开销。不过,有点巧妙的想法,如果我可以篡改特定托管对象上下文的模型,它可能会起作用......但是,作为第二个潜在问题,我认为 NullifyDeleteRule 仍然会执行关系查找(至少在多对多中)所以它可以取消(或删除)关系行:(可能会快一点,但我想完全跳过检查。
  • 当它们在同一个堆栈中时,更改特定上下文的删除规则不起作用,因为您必须在模型级别进行更改。另一种可能有效的方法是使用 NSNoActionDeleteRule 但覆盖 prepareForDeletion 以自己处理级联效应。
  • 这条最新评论应该是您的答案。将其设置为 NSNoActionDeleteRule 然后在 prepareForDeletion 中自己管理删除确实允许选择删除计算发生的时间和频率。 -- 关于您对性能的问题,在我们的例子中,我们使用的是自定义 SQL 支持的 NSIncrementalStore -- 删除所涉及的 CPU 的 70% 被“newFetchToManyRelationship”占用,主要是因为关系中的一个表具有大量记录。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多