关注公众号学习更多知识
概述
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
}
插入数据后表的结构
插入数据后父亲的表结构:
儿子的表结构:
儿子的表中并不会被真实的插入数据