Search code examples
androidkotlinrealmrlmlinkingobjects

How to use LinkingObject for android


I would like to make a relationship like SQLite using Realm.

  1. If don't have a child table when add a parent table, how do add RealmList?
  2. Is there a real-time link between the parent table and the child table?
  3. How to migration RealmList, @LinkingObject

1.Parent Table

@RealmClass
open class ParentTable : RealmObject() {

    @PrimaryKey
    open var id : Long = 0

    open var parentname : String? = null

    var child : RealmList<ChildTable>? = null

}

2.Child Table

@RealmClass
open class ChildTable : RealmObject() {

    @PrimaryKey
    open var id : Long = 0

    open var parentId : Long? = 0    

    open var childName : String? = null

    @LinkingObjects("child")
    val parent : RealmResults<ParentTable>? = null

}

3.Application class

class HanmoApplication : MultiDexApplication() {

    override fun onCreate() {
        super.onCreate()

        initRealm()
    }

    private fun initRealm() {

        Realm.init(this)

        val config = RealmConfiguration.Builder()
                .name("hanmo.realm")
                .deleteRealmIfMigrationNeeded()
                .build()

        Realm.setDefaultConfiguration(config)
    }

    override fun onTerminate() {
        super.onTerminate()
        if (!Realm.getDefaultInstance().isClosed) {
            Realm.getDefaultInstance().close()
        }
    }
}

4.RealmHelper class

class RealmHelper {

var realm: Realm
    private set

init {
    realm = try {

        Realm.getDefaultInstance()

    } catch (e: Exception) {

        Log.d("Realm Exception", e.toString())

        val config = RealmConfiguration.Builder()
                .deleteRealmIfMigrationNeeded()
                .build()
        Realm.getInstance(config)
    }
}

fun selectTables() {
    val parent = queryAll(ParentTable::class.java)
    Log.d("parent", parent.toString())

    parent?.forEach {
        it.child?.forEach {
            Log.d("parent.child", it.toString())
        }
    }

    val child = queryAll(ChildTable::class.java)
    Log.d("child", child.toString())

    child?.forEach {
        Log.d("child.parent", it.parent?.toString())
    }
}

fun insertParent() {

    val parent = ParentTable()
    parent.id = 1
    parent.parentname = "First Parent"

    val childList = RealmList<ChildTable>()
    val child = queryAll(ChildTable::class.java)

    child?.forEach {
        val child = ChildTable()
        child.id = it.id
        child.childName = it.childName

        childList.add(child)
    }

    parent.child = childList

    addRealmListData(parent)
}


fun insertChild() {
    val maxId = realm.where(ChildTable::class.java).max("id")
    val nextId : Long =
            when(maxId) {
                null -> { 1 }
                else -> { maxId.toLong() + 1 }
            }

    val parentId = realm.where(ParentTable::class.java).findFirst()
    val child = ChildTable()
    child.id = nextId
    child.childName = "child num : $nextId"
    child.parentId = parentId?.id

    addData(child)
}

//Insert To Realm
fun <T : RealmObject> addData(data: T) {
    realm.executeTransaction {
        realm.copyToRealm(data)
    }
}

//Insert To Realm with RealmList
fun <T : RealmObject> addRealmListData(data: T) {
    realm.executeTransaction {
        realm.copyToRealmOrUpdate(data)
    }
}

fun <T : RealmObject> queryAll(clazz: Class<T>): RealmResults<T>? {
    return realm.where(clazz).findAll()
}

companion object {

    private var INSTANCE: RealmHelper? = RealmHelper()

    val instance: RealmHelper
        get() {
            if (INSTANCE == null) {
                INSTANCE = RealmHelper()
            }
            return INSTANCE as RealmHelper
        }
}

}

5.MainActivity class

class MainActivity : AppCompatActivity() {

lateinit var compositeDisposable: CompositeDisposable

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    compositeDisposable = CompositeDisposable()

    initParentTable()
    setButtonClick()
}

private fun initParentTable() {

    val parentTable = RealmHelper.instance.queryAll(ParentTable::class.java)

    if (parentTable?.isEmpty()!!){
        RealmHelper.instance.insertParent()
    }

}

private fun setButtonClick() {

    btn_addchild.clicks()
            .subscribe {
                RealmHelper.instance.insertChild()
            }.apply { compositeDisposable.add(this) }

    btn_parentquery.clicks()
            .subscribe {
                RealmHelper.instance.selectTables()
            }.apply { compositeDisposable.add(this) }

}

override fun onDestroy() {
    compositeDisposable.clear()
    super.onDestroy()
}

}

this is realm query log

fun selectTables() {
    val parent = queryAll(ParentTable::class.java)
    Log.d("parent", parent.toString())

    parent?.forEach {
        it.child?.forEach {
            Log.d("parent.child", it.toString())
        }
    }

    val child = queryAll(ChildTable::class.java)
    Log.d("child", child.toString())

    child?.forEach {
        Log.d("child.parent", it.parent?.toString())
    }
}

Click on addChild button three times, query, and see results

03-26 12:22:17.534 29996-29996/com.hanmo.testforlinkingobject D/parent: [ParentTable = proxy[{id:1},{parentname:First Parent},{child:RealmList<ChildTable>[0]}]]
03-26 12:22:17.535 29996-29996/com.hanmo.testforlinkingobject D/child: [ChildTable = proxy[{id:1},{parentId:1},{childName:child num : 1}], ChildTable = proxy[{id:2},{parentId:1},{childName:child num : 2}], ChildTable = proxy[{id:3},{parentId:1},{childName:child num : 3}]]
03-26 12:22:17.536 29996-29996/com.hanmo.testforlinkingobject D/child.parent: []
03-26 12:22:17.536 29996-29996/com.hanmo.testforlinkingobject D/child.parent: []
03-26 12:22:17.537 29996-29996/com.hanmo.testforlinkingobject D/child.parent: []

=> Parent Table and Child Table are not linked.

please How to add a RealmList when there is no Child Table


Solution

  • If don't have a child table when add a parent table, how do add RealmList?

    You need to have the Child class to add a RealmList<Child>.

    Relationships can be built using managed objects, in a transaction.

    r.executeTransaction((realm) -> {
        ...
        Child child = realm.createObject(Child.class);
        Parent parent = realm.where(Parent.class)./*...*/.findFirst();
        parent.getChildren().add(child);
        ...
    }
    

    Is there a real-time link between the parent table and the child table?

    yes

    How to migration RealmList, @LinkingObject

    Add RealmList<T> using realmObjectSchema.addRealmListField() method.

    @LinkingObjects are computed and not part of the schema, so no migration needed for that.