NSMigrationManager.migrateStore 与 NSPersistentHistoryTrackingKey

Mac*_*cMc 6 core-data-migration

我有一个核心数据实现。该堆栈是使用 NSPercientContainer 加载的。在设置过程中,我在 NSPersistentStoreDescription 上设置了 NSPersistentHistoryTrackingKey。

description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
Run Code Online (Sandbox Code Playgroud)

我正在尝试沿着这条线实现渐进式迁移https://williamboles.me/progressive-core-data-migration/(顺便说一句,这是一篇很棒的文章!)

我遇到的第一个问题是在 WAL 中强制设置检查点。代码非常简单:

func forceWALCheckpointingForStore(at storeURL: URL) {
guard let metadata = NSPersistentStoreCoordinator.metadata(at: storeURL), let currentModel = NSManagedObjectModel.compatibleModelForStoreMetadata(metadata) else {
    return
}

do {
    let persistentStoreCoordinator = NSPersistentStoreCoordinator(managedObjectModel: currentModel)

    let options = [NSSQLitePragmasOption: ["journal_mode": "DELETE"]]
    let store = persistentStoreCoordinator.addPersistentStore(at: storeURL, options: options)
    try persistentStoreCoordinator.remove(store)
} catch let error {
    fatalError("failed to force WAL checkpointing, error: \(error)")
  }
}
Run Code Online (Sandbox Code Playgroud)

当 NSPersistentStoreCoordinator 运行 addPersistentStore 时会出现此问题。我收到以下错误:

存储在没有 NSPersistentHistoryTrackingKey 的情况下打开,但之前已使用 NSPersistentHistoryTrackingKey 打开 - 强制进入只读模式存储在 url...

这是完全有道理的。核心数据框架创建了额外的表(NSPersistentHistoryToken、NSPersistentHistoryTransaction 等),您可以访问这些表来管理历史记录中的更改。如果您在没有历史记录跟踪选项的情况下“打开”或“访问”数据库,Core Data 框架会将数据库置于只读模式以避免数据完整性问题。

据我在文档中看到, NSPersistentHistoryTrackingKey 只能在容器上设置,而不能直接在 NSPersistentStoreCoordinator 上设置(通过选项)。

为了保持“在容器的边界内”,我决定在容器的“persistentStoreCoordinator”属性上调用 addPersistentStore(使用 Pragmas 选项)。这种方法的问题在于容器是使用最新版本的 NSManagedObjectModel 实例化的。因为我们正处于迁移过程的中间,所以迁移还没有发生。尝试以任何方式通过容器内的存储协调器操作存储都会导致此错误:

The model used to open the store is incompatible with the one used to create the store.

I had to therefore instantiate a container with the existing version of the model. Further research also revealed that I can force a WAL checkpoint via the NSPersistent container (and avoid having to use the coordinator) by setting the following option on the container description:

description.setValue("DELETE" as NSObject, forPragmaNamed: "journal_mode")
Run Code Online (Sandbox Code Playgroud)

I created a temporary pre-migration container, instantiated it with the current (old) version of the managed object model, and set the above pragmas option to force a WAL checkpoint. It worked like a charm! The existing database was now ready to be migrated to the new model version(s).

The migration process kicks off and I hit a wall here:

NSMigrationManager.migrateStore(from: currentURL, sourceType: NSSQLiteStoreType, options: nil, with: mappingModel, toDestinationURL: destinationURL, destinationType: NSSQLiteStoreType, destinationOptions: nil)
Run Code Online (Sandbox Code Playgroud)

Once again, we're back to the original problem:

Store opened without NSPersistentHistoryTrackingKey but previously had been opened with NSPersistentHistoryTrackingKey - Forcing into Read Only mode store at url...

I want to migrate my database WITH the history tracking option enabled. After all, the history tracking tables created by the Core Data framework must also be migrated to the new version of the database. But, I don't know how to achieve this with the available Core Data classes. It is always best to stay as close to the vendor recommended implementations as possible and not do weird workarounds.

Here's what I know:

  • With lightweight migration options set on my Container, I can create new model versions to my heart's content!
  • With the NSPersistentHistoryTrackingKey also set on the same container, the Core Data framework automatically migrates my store from one model version to the next without missing a beat!
  • Therefore, if I now want to migrate my database manually with all the options set on the container, I should be able to do it because if Core Data can do it, I should be able to do it.... yes?

关于这些问题的文档有点简单。这里发生了两件事之一。要么文档没有更新,要么......我正在尝试做人类已知的最奇怪的事情,它永远不应该做......永远......