即使添加映射模型后,CoreData 轻量级迁移也会崩溃

koe*_*oen 1 core-data ios mapping-model cloudkit

在我的 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
Run Code Online (Sandbox Code Playgroud)

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

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

但我仍然收到错误。

shouldMigrateStoreAutomaticallyshouldInferMappingModelAutomatically设置为true

我在这里缺少什么?

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

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

Tom*_*ton 5

简而言之,即使使用映射模型,自动轻量级迁移也无法实现此更改。您需要执行完整的手动迁移才能进行此更改。如果你查看苹果的轻量级迁移文档,它说

...如果两个现有实体在源中不共享公共父实体,则它们无法在目标中共享公共父实体。

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

关于原因的较长答案涉及核心数据如何工作的一些细节。Xcode 并没有很好地让这一点变得显而易见。

  • 当您有两个或多个没有共同父实体的实体时,Core Data 会将它们视为完全独立的。你的 SQLite 有一个Book表、一个Author表等等。
  • 当您有两个或多个具有共同父级的实体时,Core Data 会将它们视为同一个表的特殊情况。你的 SQLite 有一个IDManagedObject表。核心数据使用其他逻辑来确定该表中的条目是否是 aBook或 anAuthor或其他内容。

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

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

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