核心数据在一对多关联中双重插入子记录

Core Data double-inserting child records in one-to-many association

我们有一个 iOS 应用程序,它使用 Core Data 来保存从私人网站 API 获取的记录。我们的一个 API 请求获取 Project 记录的列表,每个记录都有多个关联的 Location 记录。 ObjectMapper 用于反序列化 JSON 响应,我们有一个自定义转换器,将嵌套的 Location 属性分配给 Project 实体上的核心数据关联。

代码的相关部分如下所示。它在 PromiseKit promise(因此是 seal)中执行,我们首先保存到后台上下文,然后传播到在 UI 线程上使用的主上下文。

WNManagedObjectController.backgroundContext.perform {
    let project = Mapper<Project>().map(JSONObject: JSON(json).object)!

    try! WNManagedObjectController.backgroundContext.save()

    WNManagedObjectController.managedContext.performAndWait {
        do {
            try WNManagedObjectController.managedContext.save()
            seal.fulfill(project.objectID)
        } catch {
            seal.reject(error)
        }
    }
}

我们遇到的问题是此插入过程将每个 Location 记录保存到数据库 两次 。奇怪的是,重复的 Location 记录与其父 Project 记录没有任何关联。也就是说,如果使用 NSFetchRequest 查找 Location 记录,或者如果我 运行 对底层 SQLite 数据库进行查询,我可以看到每个 [= 有两个条目=12=],但 project.locations 每个 Location 只有 returns 一份。应用于具有相同结构的其他记录类型的相同(或非常相似)过程也会导致重复。

到目前为止,我已经尝试了几种方法来缩小问题范围:

该列表中的最后一项有效地解决了问题,但它是治标不治本。数据完整性对我们的应用程序很重要,我希望了解潜在的问题可能是什么,或者我可能会寻求其他选项来进一步调查它。

谢谢!

一年零八个月后,当不同的记录集发生类似问题时,我终于找到了这个错误的根源。问题是我在每个 Location 对象上调用了 ObjectMapper 两次。我在自定义 ObjectMapper TransformType 中使用 ObjectMapper 的 mapArray 方法反序列化并保留与每个 Project 关联的 Location 记录,其工作方式如下:

let locations = Mapper<Location>().mapArray(JSONObject: value as AnyObject)

但是,我忽略的是我还重写了 Location 的构造函数并在那里再次调用 ObjectMapper

required public init?(map: Map) {
    let entity = NSEntityDescription.entity(forEntityName: "Location", in: WNManagedObjectController.backgroundContext)
    super.init(entity: entity!, insertInto: WNManagedObjectController.backgroundContext)
    mapping(map: map)
}

mapping(map: map) 是不必要的,事实证明是罪魁祸首。在具有两个级别的一对多关联的类似场景中,这具有将第二级别的记录翻四倍(!)的有点有趣的结果 - 它们的父项已被复制,每个副本随后复制其子项。这就是最终导致错误的原因。