首页 > 解决方案 > Realm Swift 错误:无法直接创建嵌入式对象

问题描述

我正在尝试将具有 type 属性的对象迁移List<String>到 type List<ChildObject>where ChildObjectis a custom EmbeddedObject

例子

这就是我的意思:

import RealmSwift

final class ParentObject: Object {
    // Previously, this property was of type `List<String>`.
    @Persisted public var children: List<ChildObject>
}

final class ChildObject: EmbeddedObject {
    @Persisted var name = ""
}

我正在使用此代码执行迁移,这会产生错误:

不能直接创建嵌入对象

let configuration = Realm.Configuration(schemaVersion: 1) { migration, oldSchemaVersion in
    if oldSchemaVersion < 1 {
        migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
            let childrenStrings = oldObject!["children"] as! List<DynamicObject>
            let childrenObjects = newObject!["children"] as! List<MigrationObject>

            // I'm trying to retain the previous values for `children` (of type `String`) 
            // where each value is used as the `name` property of a new `ChildObject`.
            for string in childrenStrings {
                childrenObjects.append(
                    // This line produces the error :(
                    migration.create(ChildObject.className(), value: [string])
                )
            }
        }
    }
}

let realm = try! Realm(configuration: configuration)

问题

如何在保留先前值的同时执行迁移?

标签: swiftrealmrealm-migrationrealm-embedded-object

解决方案


最简单的做法是Dictionary使用每个子对象的所有属性名称/值对创建一个,并List使用这些对的数组创建一个完整的新对象。

但首先您需要String从旧Listchildren. 这是必要的原因是因为 Realm 并不将元素表示List<String>为实际的String(它是一个结构)。description我们可以从字段中提取实际值:

childrenStrings
    .map { String(describing: $0) }

一旦你有了名字,你就可以ChildObjectDictionary. 请注意,您必须在Dictionary. 由于我们只有一个,称为“名称”,因此我们包括:

childrenStrings
    .map { String(describing: $0) }
    .map { ["name": $0] }

你的错误信息说:

不能直接创建嵌入对象

但是,您可以使用对应的Array和每个对应的对象来创建新对象。综上所述,我们有:DictionaryArrayListDictionaryChildObject

migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
    let childrenStrings = oldObject!["children"] as! List<DynamicObject>

    newObject?.setValue(
        Array(
            childrenStrings
                .map { String(describing: $0) }
                .map { ["name": $0] }
        ),
        forKey: "children"
    )
}

推荐阅读