android-Room通过大头儿子的故事讲讲对象关系

关注公众号学习更多知识

概述

sqlite是一个关系型数据库,因此对象关系就是重要的一部分,例如我们定义的数据中有森林和树木,森林包含树木。此时定义的森林中应该包含于一个树木的对象,这便是森林和树木的对象关系

关系类型

多个对象之间的关系有以下四种:

  • 一对一
  • 一对多
  • 多对多
  • 嵌套

一对一

举例:独生子 一个爸爸有一个儿子,这便是一对一的对对象关系

代码
class RoomRelativeActivity : CustomAdapterActivity() {
    private lateinit var database: OurRoomDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        database=Room.databaseBuilder(this,OurRoomDatabase::class.java,"parentsun").build()
    }
    override fun getAdapterDatas(): MutableList<ItemData> = mutableListOf(
        ItemData(title = "插入一爹") {
            lifecycleScope.launch {
                val parent = Parent("小头爸爸")
                database.parentSunDao().insertParent(parent)
                it.itemData.content="插入成功"
                it.itemData.notifyDataSetChange()
            }
        },
        ItemData(title = "插入一个儿子"){
               lifecycleScope.launch {
                   val sun=Sun("大头儿子",1)
                   database.parentSunDao().insertSun(sun)
                   it.itemData.run {
                       content="插入成功"
                       notifyDataSetChange()
                   }
               }
        },
        ItemData(title = "查询数据"){
            lifecycleScope.launch {
                var parentAndSun = database.parentSunDao().queryParent(1)
                val content = "父亲是:${parentAndSun.parent}  \n儿子是: ${parentAndSun.sun}"
                it.itemData.content=content
                it.itemData.notifyDataSetChange()
            }
        }
    )

    override fun showFirstItem(): Boolean = false
}
@Dao
interface ParentSonDao {
    @Transaction
    @Insert
    suspend fun insertParent(parent: Parent)//插入父亲

    @Insert
    suspend fun insertSun(sun: Sun)//插入儿子

    /**
     * 查询父亲和儿子的组合
     */
    @Transaction
    @Query("select * from Parent where parentId=:parentId")//查询父亲和和儿子的集合,注意我们无法直接插入ParentAndSunRef
    suspend fun queryParent(parentId: Long): ParentAndSunRef
}

/**
 * 用来表示Parent和Sun的集合,如果我们想同事查询父亲和儿子可以使用父亲id查询
 */
data class ParentAndSunRef(//我们不需要给ParentAndSunRef添加@Entity注解
    @Embedded
    val parent: Parent,//
    @Relation(
        parentColumn = "parentId",//儿子关联父亲的主键parentId
        entityColumn = "hisparentId"//父亲中必须存入儿子的某个唯一id字段hisparentId
    )
    val sun: Sun
)

/**
 * 父亲
 */
@Entity
data class Parent(var name: String) {
    @PrimaryKey(autoGenerate = true)
    var parentId: Long? = null
}

/**
 * 儿子
 */
@Entity
data class Sun(var name: String,var hisparentId:Long) {
    @PrimaryKey(autoGenerate = true)
    var sunId: Long? = null
}
实现效果

数据库结构
  1. Parent表

  1. Sun表

一对多

上一节中是独生子女,所以一个爹对应一个儿子,本例中就不是独生子女了,一个爹可以有多个儿子。

例如:围裙妈妈给大头儿子生了一个弟弟,此时小头爸爸就有两个儿子,关系类中儿子的选项就不能是一个对象了,而应该是一个列表。

所以一对多的使用与一对一的关系基本差不多,只不过对应关系中儿子类用一个列表表示。

代码

class OneToManyActivity : CustomAdapterActivity() {

    private lateinit var database: OurRoomDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        database = Room.databaseBuilder(this,OurRoomDatabase::class.java,"parent1andsun1").build()
    }
    override fun getAdapterDatas(): MutableList<ItemData> = mutableListOf(
        ItemData("插入一个爹"){
            lifecycleScope.launch {
                val parent=Parent1("小头爸爸")
                database.parent1AndSun1Dao().insertParent1(parent)
                it.itemData.run {
                    content="插入成功"
                    notifyDataSetChange()
                }
            }
        },
        ItemData("插入一个儿子"){
            lifecycleScope.launch {
                val sun = Sun1("大头儿子",1)
                database.parent1AndSun1Dao().insertSun1(sun)
            }
            it.itemData.run {
                content="插入成功"
                notifyDataSetChange()
            }
        },
        ItemData("插入第二个儿子"){
            lifecycleScope.launch {
                val sun = Sun1("大头儿子的弟弟",1)
                database.parent1AndSun1Dao().insertSun1(sun)
            }
            it.itemData.run {
                content="插入成功"
                notifyDataSetChange()
            }
        },
        ItemData(title = "查询一个爹和两个儿子"){
            lifecycleScope.launch {
                val parentAndSunRef = database.parent1AndSun1Dao().queryParent1AndSun1(1)
                val con = "父亲是:${parentAndSunRef.parent.name} " +
                        "\n 第一个儿子是:${parentAndSunRef.sun1s[0].name} " +
                        "\n 第二个儿子是:${parentAndSunRef.sun1s[1].name}"
                it.itemData.run {
                    content=con
                    notifyDataSetChange()
                }
            }
        }
    )

    override fun showFirstItem(): Boolean =false
}
@Dao
interface Parent1AndSun1Dao{
    @Insert
    suspend fun insertParent1(parent: Parent1)
    @Insert
    suspend fun insertSun1(parent: Sun1)
    /**
     * 查询父亲和儿子的集合,这里必须要有@Transaction注解,目的是保准原子操作
     */
    @Transaction
    @Query("select * from Parent1 where parentId=:parentId")
    suspend fun queryParent1AndSun1(parentId:Long):Parent1AndSun1Ref
}
@Entity
data class Parent1(var name:String){
    @PrimaryKey(autoGenerate = true)
    var parentId:Long?=null
}
@Entity
data class Sun1(var name:String,var refparentId:Long){
    @PrimaryKey(autoGenerate = true)
    var sunId:Long?=null

}
data class Parent1AndSun1Ref(
    @Embedded
    val parent:Parent1,
    @Relation(
        parentColumn = "parentId",//这里使用parentColumn
        entityColumn = "refparentId"
    )
    val sun1s:List<Sun1>
)
效果

多对多

上面的例子是一个父亲对应多个儿子,但是我们都知道大头儿子、小头爸爸、隔壁老王的关系是众所周知的。这中间可能存在多对多的关系,本例就讲一下这种多对多的关系。

实现这种多对多的关系,需要定义多个关系,

比如一个爹有多个儿子就需要定义Parent2Suns的关系类;

一个儿子有两个父亲的情况需要定义Sun2Parents的关系类;

代码

class ManyToManyActivity : CustomAdapterActivity() {
    private lateinit var database: OurRoomDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        database = Room.databaseBuilder(this, OurRoomDatabase::class.java, "parent2AndSun2").build()
    }

    override fun getAdapterDatas(): MutableList<ItemData> = mutableListOf(
        ItemData(title = "插入小头爸爸") {
            lifecycleScope.launch {
                val parent = Parent2("小头爸爸", 1)
                database.parent2AndSun2Dao().insertParent2(parent)
            }
        },
        ItemData(title = "插入隔壁老王") {
            lifecycleScope.launch {
                val parent = Parent2("隔壁老王", 1)
                database.parent2AndSun2Dao().insertParent2(parent)
            }
        },
        ItemData(title = "插入大头儿子") {
            lifecycleScope.launch {
                val sun = Sun2("大头儿子", 1)
                database.parent2AndSun2Dao().insertSun2(sun)
            }
        },
        ItemData(title = "插入大头儿子的弟弟") {
            lifecycleScope.launch {
                val sun = Sun2("大头儿子的弟弟", 1)
                database.parent2AndSun2Dao().insertSun2(sun)
            }
        },
        ItemData(title = "查询儿子") {
            lifecycleScope.launch {
                val parent = database.parent2AndSun2Dao().queryParent(1)
                logEE(parent.toString())
            }
        }
    )

    override fun showFirstItem(): Boolean = false
}
@Dao
interface Parent2AndSun2Dao {
    @Insert
    suspend fun insertParent2(parent: Parent2)

    @Insert
    suspend fun insertSun2(sun: Sun2)

    @Transaction
    @Query("select * from Parent2 where combineId=:combineId")
    suspend fun queryParent(combineId: Long): Parent2Sun2Ref

    @Transaction
    @Query("select * from Sun2 where combineId=:combineId")
    suspend fun querySun(combineId: Long): Sun2Parent2Ref
}

@Entity
data class Parent2(var name: String, var combineId: Long) {
    @PrimaryKey(autoGenerate = true)
    var parentId: Long? = null
}

@Entity
data class Sun2(var name: String, var combineId: Long) {
    @PrimaryKey(autoGenerate = true)
    var sunId: Long? = null
}

data class Parent2Sun2Ref(
    @Embedded
    var parent: Parent2,
    @Relation(
        parentColumn = "combineId",
        entityColumn = "combineId"
    )
    var sun: List<Sun2>
)

data class Sun2Parent2Ref(
    @Embedded
    var sun: Sun2,
    @Relation(
        parentColumn = "combineId",
        entityColumn = "combineId"
    )
    var parent: List<Parent2>
)
效果图

嵌套

上面的三个小结中我们使用@Embdded和@Relation注解实现了数据库间的关系映射,

实际上抛开@Relation,@Embdded单独仍然可以实现对象的嵌套。

例如本例中我们再Parent3中使用@Embdded嵌套Sun3,Sun3中的字段会被复制到Parent3中的表中,

代码
package com.ananananzhuo.roomdemo.embdded

import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.room.*
import com.ananananzhuo.mvvm.activity.CustomAdapterActivity
import com.ananananzhuo.mvvm.bean.bean.ItemData
import com.ananananzhuo.roomdemo.OurRoomDatabase
import kotlinx.coroutines.launch

/**
 * author  :mayong
 * function:对象之间的嵌套
 * date    :2021/9/12
 **/
class EmbddedActivity : CustomAdapterActivity() {
    private lateinit var database: OurRoomDatabase

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        database = Room.databaseBuilder(this,OurRoomDatabase::class.java,"parent3AndSun3").build()
    }
    override fun getAdapterDatas(): MutableList<ItemData> = mutableListOf(
        ItemData(title = "插入小头爸爸"){
            lifecycleScope.launch {
                database.parent3AndSun3Dao().insertParent(Parent3("小头爸爸", Sun3("大头儿子")))
            }
        },
        ItemData(title = "查询小头爸爸"){
            lifecycleScope.launch {
                val parent3 = database.parent3AndSun3Dao().queryParent(1)
                it.itemData.run {
                    content="父亲的名字:${parent3.parentName} \n 儿子的名字:${parent3.sun.sunName}"
                    notifyDataSetChange()
                }
            }
        }
    )

    override fun showFirstItem(): Boolean=false
}
@Dao
interface Parent3Sun3Dao {
    @Insert
    suspend fun insertParent(parent3: Parent3)

    @Insert
    suspend fun insertSun(sun: Sun3)

    @Query("select * from Parent3 where parentId=:parentId")
    suspend fun queryParent(parentId: Long): Parent3
}

@Entity
data class Parent3(
    var parentName: String,
    @Embedded
    var sun: Sun3
){
    @PrimaryKey(autoGenerate = true)
    var parentId: Long? = null
}

@Entity
data class Sun3(
    var sunName: String
){
    @PrimaryKey(autoGenerate = false)
    var sunId: Long? = null
}
插入数据后表的结构

插入数据后父亲的表结构:

儿子的表结构:

儿子的表中并不会被真实的插入数据

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值