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

简介: Room-通过大头儿子的故事简单讲讲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
}
复制代码


实现效果

image.png


数据库结构

  1. Parent表

image.png

  1. Sun表

image.png


一对多

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

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

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


代码

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>
)
复制代码

效果

image.png


多对多

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

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

比如一个爹有多个儿子就需要定义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>
)
复制代码


效果图

image.png


嵌套

上面的三个小结中我们使用@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
}
复制代码


插入数据后表的结构

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

image.png

儿子的表结构:

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

image.png


相关文章
|
2月前
|
JavaScript 前端开发 搜索推荐
快收藏!超实用标签title属性重写,让同事对你刮目相看
【10月更文挑战第1天】快收藏!超实用标签title属性重写,让同事对你刮目相看
114 10
快收藏!超实用标签title属性重写,让同事对你刮目相看
|
编译器 C++
C++ :类 和 对象 ※重点※(二)
C++ :类 和 对象 ※重点※(二)
77 0
|
Java 编译器 C++
C++ :类 和 对象 ※重点※(三)
C++ :类 和 对象 ※重点※(三)
86 0
|
编译器 C++
C++ :类 和 对象 ※重点※(一)
C++ :类 和 对象 ※重点※
50 0
AVPlayerItem、AVPlayer、AVPlayerLayer三者关系
AVPlayerItem、AVPlayer、AVPlayerLayer三者关系
84 0
小满Router(第六章-命名视图)
命名视图可以在同一级(同一个组件)中展示更多的路由视图,而不是嵌套显示。 命名视图可以让一个组件中具有多个路由渲染出口,这对于一些特定的布局组件非常有用。 命名视图的概念非常类似于“具名插槽”,并且视图的默认名称也是 default。
74 0
|
存储 安全 算法
《我要进大厂》- Java集合夺命连环14问,你能坚持到第几问?(集合概述 | List | Set | Queue)
《我要进大厂》- Java集合夺命连环14问,你能坚持到第几问?(集合概述 | List | Set | Queue)
《我要进大厂》- Java集合夺命连环14问,你能坚持到第几问?(集合概述 | List | Set | Queue)
|
设计模式 缓存 前端开发
理清Activity、View及Window之间关系
理清Activity、View及Window之间关系
|
Java
Java初学者作业——定义英雄类(Hero),英雄类中的属性包括:姓名、攻击力、防御力、生命值和魔法值;方法包括:攻击、介绍。
Java初学者作业——定义英雄类(Hero),英雄类中的属性包括:姓名、攻击力、防御力、生命值和魔法值;方法包括:攻击、介绍。
1395 1
|
前端开发 JavaScript
前端百题斩【016】——原型、构造函数和实例之间的奇妙关系
前端百题斩【016】——原型、构造函数和实例之间的奇妙关系
前端百题斩【016】——原型、构造函数和实例之间的奇妙关系