CoreData 轻量级迁移崩溃,即使在添加映射模型后也是如此

CoreData lightweight migration crashes, even after adding a mapping model

在我的 CoreData 模型中,我创建了一个抽象实体 (IDManagedObject) 来为我的其他实体共享一个公共属性。

当我第一次 运行 它时,我遇到了几个 Cannot merge multiple root entity source tables into one destination entity root table 错误。

完整错误如下:

Fatal error: Unresolved error Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={sourceURL=file:///Users/koen/Library/Developer/CoreSimulator/Devices/8E2C0F01-ABF3-4414-A01A-EE4FFEF8D187/data/Containers/Data/Application/B7A9A4EE-EB57-434F-B1A9-576DCD80CFBD/Library/Application%20Support/MyApp.sqlite, reason=Cannot migrate store in-place: Cannot merge multiple root entity source tables into one destination entity root table, destinationURL=file:///Users/koen/Library/Developer/CoreSimulator/Devices/8E2C0F01-ABF3-4414-A01A-EE4FFEF8D187/data/Containers/Data/Application/B7A9A4EE-EB57-434F-B1A9-576DCD80CFBD/Library/Application%20Support/MyApp.sqlite, NSUnderlyingError=0x6000019fb810 {Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={message=Cannot merge multiple root entity source tables into one destination entity root table, destinationRootEntity=IDManagedObject, NSUnderlyingException=Cannot merge multiple root entity source tables into one destination entity root table, sourceRootEntities=(
    Book,
    Author
), reason=Cannot merge multiple root entity source tables into one destination entity root table}}}, ["NSUnderlyingError": Error Domain=NSCocoaErrorDomain Code=134110 "An error occurred during persistent store migration." UserInfo={message=Cannot merge multiple root entity source tables into one destination entity root table, destinationRootEntity=IDManagedObject, NSUnderlyingException=Cannot merge multiple root entity source tables into one destination entity root table, sourceRootEntities=(
    Book,
    Author
), reason=Cannot merge multiple root entity source tables into one destination entity root table}, "destinationURL": file:///Users/koen/Library/Developer/CoreSimulator/Devices/8E2C0F01-ABF3-4414-A01A-EE4FFEF8D187/data/Containers/Data/Application/B7A9A4EE-EB57-434F-B1A9-576DCD80CFBD/Library/Application%20Support/MyApp.sqlite, "sourceURL": file:///Users/koen/Library/Developer/CoreSimulator/Devices/8E2C0F01-ABF3-4414-A01A-EE4FFEF8D187/data/Containers/Data/Application/B7A9A4EE-EB57-434F-B1A9-576DCD80CFBD/Library/Application%20Support/MyApp.sqlite, "reason": Cannot migrate store in-place: Cannot merge multiple root entity source tables into one destination entity root table]: file MyApp/SceneDelegate.swift, line 96

有趣的是,它只显示了这两个实体的错误,但我还有更多。

经过一番搜索后 我发现我需要添加一个映射模型来在新旧版本之间迁移。所以我在 Xcode 中通过 Cmd-N 添加了它并选择了源和目标模型。

但我仍然收到错误。

shouldMigrateStoreAutomaticallyshouldInferMappingModelAutomatically都设置为true

我在这里错过了什么?

旧模型在当前应用中写成Objective-C,新模型在新版本应用中写成Swift,现在也用CloudKit。使用 Xcode 12.2.

如果需要,我很乐意添加更多信息,只是不知道什么与问题相关。

简而言之,即使使用映射模型,自动轻量级迁移也无法进行此更改。您需要进行完全手动迁移才能进行此更改。如果你查看 Apple 的 lightweight migration documentation,它说

...if two existing entities do not share a common parent in the source, they cannot share a common parent in the destination.

这就是您想要做的,但它不会自动发生。

为什么 的较长答案详细介绍了 Core Data 的工作原理。 Xcode 没有很好地使这一点变得明显。

  • 当您有两个或多个没有公共父实体的实体时,Core Data 将它们视为完全独立的。你的 SQLite 有一个 Book table,一个 Author table,等等。
  • 当您有两个或多个实体 有一个共同的父实体时,Core Data 将它们视为相同 table 的特例。你的 SQLite 有一个 IDManagedObject table。核心数据使用其他逻辑来决定 table 中的条目是 Book 还是 Author 或其他东西。

正因为如此,您实际上正在做的是将多个实体合并为一个新实体。 Core Data 不知道如何自动执行此操作,这就是它在该错误消息中告诉您的内容。

Core Data 只是抱怨这两个 table,因为它们是它首先看到的。它无法处理其中任何一个的合并,它只提到了两个 table,因为它在查看其余部分之前就放弃了。

要进行此更改,您需要创建一个迁移管理器并编写代码来执行迁移。 Apple 在 Customizing the Migration Process 中对此进行了描述。或者,根据您的具体需要,可能还有其他不需要添加新父实体的解决方案。