Search code examples
javaandroidkotlinmobilerealm

Realm property changes ignored on embedded objects


I believe my issue is a fundamental misunderstanding of how Realm Kotlin works.

In my schema there is an outer RealmObject that contains a To-One relationship to another RealmObject. For example-sake, each of these contains an ignored property that references a normal Kotlin class. It looks something like this:

class OuterObject() : RealmObject {
    @PrimaryKey var _id: RealmUUID = RealmUUID.random()
    var innerObj: InnerObject? = null
    @Ignored
    var ignoredObj: NormalObject? = null
}

class InnerObject() : RealmObject {
    @PrimaryKey var _id: RealmUUID = RealmUUID.random()
    @Ignored
    var ignoredObj: NormalObject? = null
}

class NormalObject(var name: String = "")

I then pass an instance of the OuterObject (that was retrieved from Realm) into some function. This function assigns a value to the ignoredObj property of both the outer and inner object. After the function completes, only the changes to the outer object seem to be kept.

fun applyIgnoredProperties(outerObj: OuterObject) {
    outerObj.ignoredObj = NormalObject("Test1")
    outerObj.innerObj?.ignoredObj = NormalObject("Test2")
}

fun main() {
    val outerObj = OuterObject().apply {
        innerObj = InnerObject()
    }
    applyIgnoredProperties(outerObj)
    println(outerObj.ignoredObj?.name) // "Test1"
    println(outerObj.innerObj?.ignoredObj?.name) // null
}

As seen in the comments on the two println calls, accessing the name for the outer ignored object returns the actual value, while trying to do the same on the inner ignored object just gives null. This is because the ignoredObj itself it still null on the inner object.

If you remove the Realm inheritance from all of this, then the code works as expected. I've tried having the InnerObject be an EmbeddedRealmObject, didn't make a difference. What am I missing here? Any guidance is much appreciated.

EDIT

Alex's answer pointed me in the right direction. I decided to just hard copy all objects in the query itself. Providing a value for the "depth" param makes OuterObject.innerObj actually use-able.

.map {
    it.list.map { obj ->
        realm.copyFromRealm(obj, 1u)
    }
}

Solution

  • innerObj property in OuterObject is a realm object, so changes made to its ignored property wont be persisted. when you access outerObj.innerObj?.ignoredObj?.name it returns null because the ignored prop was never persisted in the db or set

    if you want changes to the ignored property of InnerObject to be persiseted, you need to make sure it's a managed realm object for example

    val innerObject = realm.copyFromRealm(outerObj.innerObj)
    innerObject?.ignoredObj = NormalObject("Test2")
    outerObj.innerObj = innerObject