如何在Kotlin中为Realm添加嵌入式对象并作为托管对象使用?
问题
现有如下简化代码:
// given foo of type Foo realm.write { val foo = findLatest(frozenFoo) requireNotNull(foo) bar = Bar().apply{barId = 123} foo.bars.add(bar) bar.baz = 456 // 无效果 println(bar.isManaged().toString()) // 输出 false }
其中Foo是RealmObject(父对象),Bar是EmbeddedRealmObject。
当前bar对象并未转为托管对象,因此添加后对它的操作仅针对普通Kotlin对象,不会写入Realm。需要解决的是:如何将bar转为托管对象以正常操作?
Realm文档仅覆盖了同时创建父对象和嵌入式对象的场景(此时可对父对象调用copyToRealm),但当前场景是已有父对象,需为其添加新的嵌入式对象。
另外,更新已有的嵌入式对象可正常工作:
// given foo of type Foo realm.write { val foo = findLatest(frozenFoo) requireNotNull(foo) bar = foo.bars.firstOrNull{it.barId == 123} bar.baz = 456 // 正常生效 println(bar.isManaged().toString()) // 输出 true }
对象定义示例:
class Foo : RealmObject { @PrimaryKey var _id: ObjectId = ObjectId() var bars: RealmList<Bar> = realmListOf() } class Bar : EmbeddedRealmObject { var barId: Int = 0 var baz: Int = 0 }
解决方案
要让新创建的Bar嵌入式对象转为托管状态,有两种可行方式:
方式1:添加后从父对象列表中获取托管实例
嵌入式对象只有关联到托管的父对象后才会成为托管对象,因此在foo.bars.add(bar)之后,从foo.bars中取出刚添加的对象,后续操作这个实例即可:
realm.write { val foo = findLatest(frozenFoo) requireNotNull(foo) val bar = Bar().apply{barId = 123} foo.bars.add(bar) // 从列表中获取刚添加的托管对象 val managedBar = foo.bars.last() managedBar.baz = 456 // 正常生效 println(managedBar.isManaged().toString()) // 输出 true }
方式2:直接创建托管的嵌入式对象
利用RealmList的createObject方法,直接在父对象的列表中创建托管的嵌入式对象,无需先创建普通Kotlin对象:
realm.write { val foo = findLatest(frozenFoo) requireNotNull(foo) // 直接在列表中创建托管的Bar对象 val bar = foo.bars.createObject().apply{barId = 123} bar.baz = 456 // 正常生效 println(bar.isManaged().toString()) // 输出 true }
也可以用copyToRealm指定父对象和关联字段来创建托管实例:
realm.write { val foo = findLatest(frozenFoo) requireNotNull(foo) val bar = copyToRealm(Bar().apply{barId = 123}, parent = foo, fieldName = "bars") bar.baz = 456 // 正常生效 println(bar.isManaged().toString()) // 输出 true }
关键原理
嵌入式对象无法独立存在,必须依附于托管的RealmObject父对象。只有当它被关联到托管父对象(如加入父对象的RealmList)后,才会转为托管状态;此时操作原普通Kotlin对象不会同步到Realm,必须操作托管实例。
内容的提问来源于stack exchange,提问作者Adam Burley
相关产品推荐
相关产品推荐

