首页 > 解决方案 > CoreData 将数据库迁移到新代码库

问题描述

我正在对应用程序进行大型更新。通过大更新读取完整的返工 - 全新的代码库从头开始但具有相同的 bundleID 以便能够在发布时放弃旧应用程序。

我目前正在研究 CoreData 迁移并且遇到了一些问题:

我想从中加载信息OldData,手动将其迁移到NewData中,然后删除中的数据OldData

我们已将 的版本复制OldData到新应用程序中,但是当我们搜索保存的对象时,没有返回任何内容。

我们返回数据库:

let coreDataManager = CoreDataManager(modelName: "OldData")
let context = coreDataManager.persistentContainer.viewContext

if try context.count(for: NSFetchRequest(entityName: "OldObjectName")) > 0 {

上下文存在但不返回任何内容。

我已经调查了 mappingModels 但这似乎要求我们能够访问旧数据才能对其进行映射,目前新应用程序中没有可用的旧数据。

似乎没有太多关于在代码库之间迁移 CoreData 的信息,而是专注于更新您正在使用的数据库的版本。

我尝试了什么:

感觉这应该比我做的容易

  1. 这甚至可能吗?- 我们是否必须使用same数据库 - 因为我们只能在原始代码库中执行此操作,因为即使旧数据库的副本也不同
  2. 我只是在配置方面做错了吗 - 数据库是否链接到项目名称或两个项目之间不同的其他内容。

使这变得稍微棘手的问题之一是我们没有任何范围来修改旧代码 - 我们只需要编写新代码来迁移旧代码。

编辑 1: 在我的调查中,我注意到两个项目数据库的代码生成是不同的 - 旧项目中的 Objective-C 和新项目中的 swift。当我最初导入OldData它时,它仍然是 Objective-C 代码生成。一旦我将它切换到 swift 旧数据库开始出现,但保存的对象仍然没有出现在我的提取中。

我不确定这是否是由语言代码生成差异引起的问题

编辑 2: 在进行一些测试后,使用不同的代码生成器语言似乎不会导致任何问题。

然而,我确实注意到 SQL 数据库存储在不同的位置:

旧的存储在Documents文件夹中,新的存储在文件Application Support夹中。这里的相关文章中提到了一些变化

这意味着问题可能是我们在不同的地方有两个 SQL 文件,这意味着数据库不是使用旧的,而是创建一个新的空文件。

我将继续关注如何在配置时将新应用程序中的旧数据库指向不同的位置。

标签: iosswiftcore-datacore-data-migration

解决方案


所以我最终找到了问题的原因和粗略的解决方案。

 private func migrateOldDatabase() {
     if let documentsPath = FileManager.default.urls(for: .libraryDirectory, in: .userDomainMask).first {
     // We need to migrate the three old sql files into the new store location
     let pathSuffixToMigrate = ["Metlink.sqlite", "Metlink.sqlite-shm", "Metlink.sqlite-wal"]

     let fileManager = FileManager.default

     for suffix in pathSuffixToMigrate {
         let path = documentsPath.appendingPathComponent(suffix)
         if fileManager.fileExists(atPath: path.path) {
            let applicationStorePath = documentsPath.appendingPathComponent("Application Support")

            do {
                let newCoredataMetlinkLocation = applicationStorePath.appendingPathComponent(suffix)
                // If there is already the same file we delete it to ensure we migrate the one we want
                if fileManager.fileExists(atPath: newCoredataMetlinkLocation.path) {
                    try fileManager.removeItem(at: newCoredataMetlinkLocation)
                }
                // We then copy the new one into its place
                try fileManager.copyItem(at: path, to: newCoredataMetlinkLocation)
            } catch {
                print("error")
            }
        }
    }
}

我们在获取持久容器之前调用它。

migrateOldDatabase()
let metlinkCoreDataManager = CoreDataManager(modelName: "Metlink")
let metlinkDBcontext = metlinkCoreDataManager.persistentContainer.viewContext

我将简要解释发生了什么。

似乎以前 CoreData 存储在 Library 文件夹中。现在虽然它默认存储在库文件夹中的应用程序支持文件夹中。这意味着当我尝试迁移系统时会寻找旧数据库,但找不到它,因此在应用程序支持中创建一个新的空数据库。

我们在这里所做的是检查我们是否在旧位置有一个,并将所有三个 sql 文件复制到新位置(同时删除旧的,如果有的话)。我发现如果我们只复制一个,就会出现问题。

我们可以在这里看到这个:

在此处输入图像描述

您可以看到我的新数据库,然后我们手动将数据迁移到其中。

我完全清楚对位置进行硬编码不是最佳解决方案,因此不建议将其作为第一种尝试方法。在我的情况下,我们只是在用户第一次加载新应用程序时尝试迁移,这意味着它不会是一个持续的危险。

值得注意的是,几乎可以肯定有比上述更正确的解决方案。我在这里找到了这篇非常有用的文章,如果您想更改 coredata 数据库的位置,这几乎肯定是正确的方法。不幸的是,由于旧版本的 coredata 导致位置不同,我无法让它工作。


推荐阅读