【问题标题】:Update property on old Realm object If not exist on new array更新旧领域对象的属性如果新数组上不存在
【发布时间】:2021-01-01 10:04:59
【问题描述】:

您好,我有一个像下面这样的领域对象。每次更新领域数据库之前,我都会获取旧对象。我想要做的是我想在新的 realmObject 数组中不存在的所有对象上将 removeMe bool 更新为 true 。我知道这看起来是一个简单的问题,但我正在寻找高效的方法。

我尝试使用 NSPrecidate 函数获取差异,但它说

无法将“NSPredicate”类型的值转换为预期的参数类型 '(ExampleClass) 抛出 -> Bool'

let predicateFilter = NSPredicate(format: "NOT (primarykey IN %@)", oldObjects)
let diff = realmObject.filter(predicateFilter)

编辑:为了清楚起见,我想解释一下我想要实现的目标。

假设具有 [A, B, C, D] 主键的现有领域对象和我的新对象具有 [A, B, D, F, G] 键然后我想将现有领域对象 removeMe 属性更改为在主键为 [C] 的对象上为 true。

可视化:

P.S: 我之所以使用 map 是因为 newArrayFromServer 不是领域对象,我将其映射到领域对象以将其写入领域数据库。

示例类:

class ExampleClass: Object {
@objc dynamic var primaryKey: Int = 0
@objc dynamic var removedDate: Date?
@objc dynamic var removedMe: Bool = false 
override static func primaryKey() -> String? {
    return "primaryKey"
}   
}

我如何写入领域数据库:

let oldObjects = Realm.getObjects(ExampleClass.self)
let realmObject = newArrayFromServer.map { (user) -> ExampleClass in
    let realmUser = ExampleClass(user: user)
    return realmUser
}
let realm = try! Realm()
try! realm.write {
    realm.add(realmObject, update: .modified)
}

我找到了一个性能不高的解决方案。下面的代码在旧数据上运行 for 循环并检查是否有任何记录在新响应中不存在并更改布尔值

let realm = try! Realm()
let oldRecords = RealmHelper.getObjects(t: ExampleClass.self)
let newFetchedRecords = backendResponse.map { (newRecord) -> ExampleClass in
    let realmUser = ExampleClass(user: newRecord)
    return realmUser
}
oldRecords.forEach { (oldRecord) in
    try! realm.write({
        if newFetchedRecords.contains(oldRecord) == false {
            oldRecord.removedMe = true
        } else {
            oldRecord.removedMe = false
        }
    })
}
try! realm.write({
    realm.add(newFetchedRecords, update: .modified)
})

【问题讨论】:

  • 一些事情。首先这个问题很不清楚——你想做什么?包含的代码是脱节的,并且变量彼此无关。第二件事是 ExampleClass primaryKey 函数似乎在类之外 - 这是故意的吗?最后一件事是,一旦从结果中删除 Realm 对象,它就不再是 Realm 对象。例如这个newArrayFromServer.map { (user) -> ExampleClass 获取所有这些对象并使它们成为非托管对象,这可能不是您想要的。请更新问题。
  • 您好,我添加更多描述以更清楚。我使用 map 的原因是因为 newArrayFromServer 不是领域对象,我将其映射到领域对象以将其写入领域数据库。
  • 目前还不清楚现有领域对象将如何“包含”在一组新创建的对象中?它们永远不会“相等”,因为它们是不同的对象。例如,您可以测试它们是否包含相同的字符串或某些其他属性,但即使您实现了 equatable 协议,Realm 对象也具有唯一的主键,因此对象不会相等。我有点明白你在尝试什么,但你能澄清什么会使 Realm oldObject 等于 newObject 因为它们的 primaryKeys 必须是唯一的?
  • 是的对象有唯一的主键。所以如果我们假设两个对象相等,它们应该有相同的私钥。
  • 您的问题指出 我调用我的后端并获取 8 个对象,这些对象在我的离线领域数据库中完全相同(具有相同的私钥) 我假设您的意思是 primary 键,而不是 private,所以这是不可能的 - 主键不能完全相同,因为它们必须是唯一的。请参阅Primary Keys 上的文档,该文档声明了 主键属性...在领域中相同类型的对象中是唯一的 以及文档 Declaring a primary key...强制每个值的唯一性

标签: ios swift realm


【解决方案1】:

你想要的是这样的:(假设你的主键是字符串类型)

let realm = try! Realm()
let oldKeySet = Set(Realm.getObjects(ExampleClass.self).map {$0.primaryKey})
let newKeySet = Set(backendResponse.map { (newRecord) -> String in
    let realmUser = ExampleClass(user: newRecord)
    return realmUser.primaryKey
})
let removedKeySet = oldKeySet.subtracting(newKeySet)
try! realm.write({
    removedKeySet.forEach {
        let object = realm.object(ofType:ExampleClass.self, forPrimaryKey: $0)
        object.removedMe = true
    }
})

【讨论】:

  • 虽然这个答案有效,但不需要Set,因为主键是唯一的(主键必须是唯一的)。同样在这里创建 ExampleClass 对象没有目的 - 它们超出了地图闭包的范围,因此不需要它们。只遍历 backendResponse 数组并从中获取 primaryKeys 会更快,代码更少。
  • 您似乎不知道 Set 用于减法运算。对于 newKeySet 部分,我同意你的最后一句话。我只是从问题中复制了代码,提问者自己会找到它。说的很清楚。
  • 哈哈。不是一个好的假设。我只是说没有必要。鉴于有一组primaryKeys,这一行将产生所需的结果let usersPrimaryKeysToUpdate = existingUserArray.filter { !newUserArray.contains($0) }。无论哪种方式,您的答案都绝对有效。
  • 我同意你的代码比我的短。过滤器部分很棒。它确实需要一些时间思考,这是我以前从未想到过并启发过我的事情。基本上,这两个答案是相同的算法,但方法不同。你的比我的深。我也从你的回答中得到了教训。非常感谢。
【解决方案2】:

让我重新陈述问题

什么是返回不在列表中的领域对象的查询?

例如:

给定现有领域对象的主键为 [1, 2, 3, 4, 5] 和 键为 [1, 3, 5] 的新对象,返回现有对象 不在新对象组中;结果将是 [2, 4]

幸运的是,只需一行代码即可完成。假设我们有一个包含 newPrimaryKeys 的 String 数组:

let examplesToUpdate = realm.objects(ExampleClass.self).filter("!(primaryKey IN %@)", newPrimaryKeys)

内容如下:获取所有现有的 ExampleClass 对象,其中它们的 primaryKey 不在 newPrimaryKey 数组中。

然后将所有examplesToUpdate removeMe属性更新为true,只需一行代码

examplesToUpdate.setValue(true, forKey: "removedMe")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 2017-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多