ios - CoreData 将数据库迁移到新代码库
问题描述
我正在对应用程序进行大型更新。通过大更新读取完整的返工 - 全新的代码库从头开始但具有相同的 bundleID 以便能够在发布时放弃旧应用程序。
我目前正在研究 CoreData 迁移并且遇到了一些问题:
- 旧应用程序只有一个数据库:
OldData
- 新应用程序将有多个数据库,但只有一个我们感兴趣:
NewData
我想从中加载信息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 的信息,而是专注于更新您正在使用的数据库的版本。
我尝试了什么:
- 我已经验证 CoreData 没有被添加到顶部的新应用程序删除。当我重新加载旧应用程序时,数据仍然存在
- 测试时,我能够在两个项目之间访问相同的 UserDefaults,这再次让我放心,数据在那里但未被访问
- 在线调查迁移教程——所有这些似乎都集中在版本之间或同一代码库内部的迁移
感觉这应该比我做的容易
- 这甚至可能吗?- 我们是否必须使用
same
数据库 - 因为我们只能在原始代码库中执行此操作,因为即使旧数据库的副本也不同 - 我只是在配置方面做错了吗 - 数据库是否链接到项目名称或两个项目之间不同的其他内容。
使这变得稍微棘手的问题之一是我们没有任何范围来修改旧代码 - 我们只需要编写新代码来迁移旧代码。
编辑 1:
在我的调查中,我注意到两个项目数据库的代码生成是不同的 - 旧项目中的 Objective-C 和新项目中的 swift。当我最初导入OldData
它时,它仍然是 Objective-C 代码生成。一旦我将它切换到 swift 旧数据库开始出现,但保存的对象仍然没有出现在我的提取中。
我不确定这是否是由语言代码生成差异引起的问题
编辑 2: 在进行一些测试后,使用不同的代码生成器语言似乎不会导致任何问题。
然而,我确实注意到 SQL 数据库存储在不同的位置:
旧的存储在Documents
文件夹中,新的存储在文件Application Support
夹中。这里的相关文章中提到了一些变化
这意味着问题可能是我们在不同的地方有两个 SQL 文件,这意味着数据库不是使用旧的,而是创建一个新的空文件。
我将继续关注如何在配置时将新应用程序中的旧数据库指向不同的位置。
解决方案
所以我最终找到了问题的原因和粗略的解决方案。
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 导致位置不同,我无法让它工作。
推荐阅读
- json - 如何编写用于将滚动条添加到 SharePoint 列表列中的单元格的 JSON 代码?
- c++ - 是在堆上分配的链表的私有成员的指针吗?
- java - 我的 AffineTransformation 像素之间有间隙
- c++ - 使用 memcpy 时,我的 RNG 函数中的内存访问失败
- android - 排球请求 - 如果 URL 错误,则无响应,如何在排球请求中检测到这种情况?
- r - 当 r 中有特殊字符时,写出插入缩进的字符值
- python - 如何将单个 df col 映射到多个“复选框”cols
- visual-studio-code - 在 vscode 上的 .ipynb 上隐藏带有运行和降价按钮的行
- rust - 为什么 BinaryHeap 需要 Ord?
- python - 为什么我的情节没有出现在使用 Tkinter 的 set_data 中?