为什么在删除时触发 Core Data NSManagedObject 错误?

Why are Core Data NSManagedObject faults fired upon deletion?

我正在尝试高效地批量删除大量 NSManagedObject(不使用 NSBatchDeleteRequest)。我一直在遵循 this answer (adapted to Swift), by batching an operation which requests objects, deletes, saves and then resets the context. My fetch request sets includesPropertyValuesfalse.

中的一般程序

但是,当它运行时,在从上下文中删除每个对象时,将触发错误。添加日志记录如下:

// Fetch one object without property values
let f = NSFetchRequest<NSManagedObject>(entityName: "Entity")
f.includesPropertyValues = false
f.fetchLimit = 1

// Get the result from the fetch. This will be a fault
let firstEntity = try! context.fetch(f).first!

// Delete the object, watch whether the object is a fault before and after
print("pre-delete object is fault: \(firstEntity.isFault)")
context.delete(firstEntity)
print("post-delete object is fault: \(firstEntity.isFault)")

产生输出:

pre-delete object is fault: true

post-delete object is fault: false

即使没有覆盖任何 CoreData 方法(willSave()prepareForDeletion()validateForUpdate() 等),也会发生这种情况。我不知道还有什么可能导致这些故障发生。


更新:我在 Swift 操场上创建了一个 simple example。这有一个单一的实体和单一的属性,没有关系。 playground删除主线程上的托管对象,从一个NSPersistentContainer的viewContext中,一个演示对象属性isFaulttrue变为false .

我认为权威的答案需要查看 Core Data 源代码。由于这不太可能实现,以下是我认为可能有必要的一些原因。

  • 对于具有关系的实体,可能需要检查关系以处理删除规则和维护数据完整性。例如,如果删除规则是 "cascade",则需要触发故障以确定应删除哪些相关实例。如果是 "nullify",则触发故障以找出哪些相关实例需要将其关系值设置为 nil。
  • 除上述之外,具有关系的实体需要对相关实例执行验证检查。例如,如果您删除一个具有使用 "nullify" 删除规则的关系的对象,并且反向关系不是可选的,那么您将无法通过反向关系的验证检查。检查这可能会触发故障。
  • 二进制属性可以让数据自动存储在外部文件中("allows external storage" 选项)。为了清理外部文件,可能需要触发故障,以便知道要删除哪个文件。

我认为所有这些都可能被优化掉。例如,如果实体没有关系并且没有使用外部存储的属性,则不要触发故障。但是,这是从外部看的,无法访问源代码。可能有其他原因需要触发故障。这似乎是可能的。或者可能是没有人出于任何原因尝试过这种优化。这似乎不太可能,但有可能。

顺便说一句,我分叉了你的 playground 代码来获得 a version that doesn't rely on an external data model file,而是用代码构建模型。

Tom Harrington 解释得最好。 CoreData 的内部实现显然需要在标记要从持久存储中删除的对象时触发错误,就像访问对象的 属性 一样。如本 "An NSManagedObject is always dynamically rendered. Hence, if it is deleted, Core Data faults out the data" 中所述。

这似乎是正常行为,至少目前不是问题。