【问题标题】:Core data - Set many-to-one relationship with NSBatchInsertRequest核心数据 - 使用 NSBatchInsertRequest 设置多对一关系
【发布时间】:2020-12-31 17:11:17
【问题描述】:

我有两个实体,UserPost。一个User 包含许多Post,而每个Post 只有一个User

我正在尝试批量插入超过 1000 个帖子。

private func newBatchInsertRequest(with posts: [PostData]) -> NSBatchInsertRequest {
    var index = 0
    let total = posts.count
    let batchInsert = NSBatchInsertRequest(entity: Post.entity()) { (managedObject: NSManagedObject) -> Bool in
        guard index < total else { return true }
        
        if let post = managedObject as? Post {
            let data = posts[index]
            post.createdData = data.createdDate
            post.identifier = data.identifier
            post.text = data.text
        }
        
        index += 1
        return false
    }
    
    PersistenceController.shared.container.performBackgroundTask { context in
        try? context.execute(batchInsert)
        try? context.save()
    }
}

它会插入我想要插入的所有帖子。但是,我无法配置如何设置他们的User

我尝试使用以下代码,但没有成功。

let updateRequest = NSBatchUpdateRequest(entity: Post.entity())
updateRequest.resultType = .updatedObjectIDsResultType
updateRequest.propertiesToUpdate = ["user": user]

 try? context.execute(updateRequest) 

我收到以下错误。

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid relationship ((<NSRelationshipDescription: 0x2801045a0>), name item, isOptional 1, isTransient 0, entity Post, renamingIdentifier item

我可以一一设置他们的用户,但是处理时间长,效率低。

如何更高效地更新 Posts 的用户属性?


更新

所有这些帖子都属于一个User,它还不存在。我需要在执行NSBatchInsertRequest之前或之后创建它。

User 具有三个属性

   1. createdDate: Date
   2. identifier: UUID
   3. name: String

我的目标是使用NSBatchInsertRequest 或在私有上下文中插入属于一个使用的帖子,这样它就不会阻塞主线程。

【问题讨论】:

  • 不清楚您如何确定应该将哪个用户连接到帖子?
  • 那为什么不先创建用户,然后分配给newBatchInsertRequest中的帖子呢?
  • 他们有不同的上下文。在核心数据中,绑定到一个上下文的对象不能在另一个上下文中使用。 @JoakimDanielson

标签: ios swift core-data


【解决方案1】:

这是我会尝试的:

  • 在批处理操作之前创建User。是的,它将在不同的环境中——只要确保你抓住它的NSManagedObjectID(它是NSManagedObject 上的一个属性)并将它保存在一个私有属性上。
  • 在您的PersistenceController.shared.container.performBackgroundTask 中,您可以引用您的私人上下文。使用之前的托管对象 ID 在您的私有上下文中获取/注册相同的 User
let user = context.object(with: userManagedObjectID)
  • 然后将此用户传递给创建批量插入请求的方法,以设置 Post 对象的用户属性。

我相信,如果您在数据模型编辑器中设置了反向关系,则无需填充 User.posts。这应该会为您自动发生。

【讨论】:

  • 谢谢。这没用。我在PersistenceController.shared.container.performBackgroundTask 之前创建了一个用户并将context.object(with: userManagedObjectID) 分配给post.user。得到这个错误:'非法尝试在不同上下文中的对象之间建立关系'u'ser
【解决方案2】:

我以不同的方式解决了这个问题。

  1. 在我的实体中需要添加关系占位符属性的 tmpID。
  2. 创建批量插入时,将 tmpID 设置为特定字符串。例如父对象ID parent.objectID
  3. 正在执行批量插入。
  4. 然后使用 tmpID 从 CoreData 获取所有对象。
  5. 然后扔掉所有人并设置:
    1. 关系
    2. tmpID 为 nil,不留内存。
  6. 保存托管对象上下文。

【讨论】:

    猜你喜欢
    • 2014-08-13
    • 1970-01-01
    • 1970-01-01
    • 2011-12-01
    • 2017-10-04
    • 2013-10-27
    • 1970-01-01
    • 2015-08-05
    • 2016-06-30
    相关资源
    最近更新 更多