Realm Swift Error: Embedded objects cannot be created directly
Realm Swift Error: Embedded objects cannot be created directly
我正在尝试将 属性 类型 List<String>
的对象迁移为类型 List<ChildObject>
,其中 ChildObject
是自定义 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 = ""
}
我正在使用此代码执行迁移,这会产生错误:
Embedded objects cannot be created directly
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)
问题
如何在保留以前的值的同时执行迁移?
最简单的方法是用每个子对象的所有 属性 name/value 对创建一个 Dictionary
,然后完整地创建新的 List
用这些对组成的数组。
但首先您需要从 children
的旧 List
中提取 String
值。这是必要的原因是因为 Realm 不将 List<String>
的元素表示为实际的 String
(这是一个结构)。我们可以从 description
字段中提取实际值:
childrenStrings
.map { String(describing: [=10=]) }
一旦你有了名字,你就可以用 Dictionary
代表新的 ChildObject
。请注意,您必须在 Dictionary
中包含所有 属性 名称和值。由于我们只有一个,称为“名称”,因此我们包括:
childrenStrings
.map { String(describing: [=11=]) }
.map { ["name": [=11=]] }
您的错误消息说:
Embedded objects cannot be created directly
但是,您可以使用 Dictionary
的 Array
创建新对象,其中 Array
对应于 List
,每个 Dictionary
对应于一个 ChildObject
对象。把它们放在一起我们有:
migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject?.setValue(
Array(
childrenStrings
.map { String(describing: [=12=]) }
.map { ["name": [=12=]] }
),
forKey: "children"
)
}
总结一下 Rob 和 Jay 的解决方案:
选项 1
这是 Rob 修改后的解决方案。
migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject!.setValue(
Array(childrenStrings.map { [[=10=]] }),
forKey: "children"
)
}
选项 2
这是基于 Jay 的建议的解决方案。它创建更少的数组(或字典,如果使用命名参数)并且应该更好地扩展更复杂的对象。
migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject!["children"] = childrenStrings.map {
let childObject = ChildObject()
childObject.name = "\([=11=])"
return childObject
} as [ChildObject]
}
我正在尝试将 属性 类型 List<String>
的对象迁移为类型 List<ChildObject>
,其中 ChildObject
是自定义 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 = ""
}
我正在使用此代码执行迁移,这会产生错误:
Embedded objects cannot be created directly
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)
问题
如何在保留以前的值的同时执行迁移?
最简单的方法是用每个子对象的所有 属性 name/value 对创建一个 Dictionary
,然后完整地创建新的 List
用这些对组成的数组。
但首先您需要从 children
的旧 List
中提取 String
值。这是必要的原因是因为 Realm 不将 List<String>
的元素表示为实际的 String
(这是一个结构)。我们可以从 description
字段中提取实际值:
childrenStrings
.map { String(describing: [=10=]) }
一旦你有了名字,你就可以用 Dictionary
代表新的 ChildObject
。请注意,您必须在 Dictionary
中包含所有 属性 名称和值。由于我们只有一个,称为“名称”,因此我们包括:
childrenStrings
.map { String(describing: [=11=]) }
.map { ["name": [=11=]] }
您的错误消息说:
Embedded objects cannot be created directly
但是,您可以使用 Dictionary
的 Array
创建新对象,其中 Array
对应于 List
,每个 Dictionary
对应于一个 ChildObject
对象。把它们放在一起我们有:
migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject?.setValue(
Array(
childrenStrings
.map { String(describing: [=12=]) }
.map { ["name": [=12=]] }
),
forKey: "children"
)
}
总结一下 Rob 和 Jay 的解决方案:
选项 1
这是 Rob 修改后的解决方案。
migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject!.setValue(
Array(childrenStrings.map { [[=10=]] }),
forKey: "children"
)
}
选项 2
这是基于 Jay 的建议的解决方案。它创建更少的数组(或字典,如果使用命名参数)并且应该更好地扩展更复杂的对象。
migration.enumerateObjects(ofType: ParentObject.className()) { oldObject, newObject in
let childrenStrings = oldObject!["children"] as! List<DynamicObject>
newObject!["children"] = childrenStrings.map {
let childObject = ChildObject()
childObject.name = "\([=11=])"
return childObject
} as [ChildObject]
}