概述
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 } 复制代码
实现效果
数据库结构
- Parent表
- 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 } 复制代码
插入数据后表的结构
插入数据后父亲的表结构:
儿子的表结构:
儿子的表中并不会被真实的插入数据