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月前
|
存储 人工智能 自然语言处理
Claude Opus 4.7 系统 Prompt 泄露:其中的10 个核心设计决策解读
刚发布的Claude 4.7 Prompt遭泄露,揭示其核心设计哲学:不只追求“更聪明”,更强调“自我约束”。它将心理重构、过度礼貌、工具犹豫等常见AI倾向视为风险信号,通过情感化规则、动态安全升级、隐式上下文记忆等10项机制,系统性抑制自身失败模式——真正目标是让模型清醒认知并管控自身的不可靠性。
231 2
Claude Opus 4.7 系统 Prompt 泄露:其中的10 个核心设计决策解读
|
Android开发
Android Studio APP开发入门之对话框Dialog的讲解及使用(附源码 包括提醒对话框,日期对话框,时间对话框)
Android Studio APP开发入门之对话框Dialog的讲解及使用(附源码 包括提醒对话框,日期对话框,时间对话框)
728 0
|
5月前
|
缓存 JavaScript PHP
Laravel12 + Vue3 的免费可商用商业级管理后台 CatchAdmin V5 正式发布
CatchAdmin V5 是基于 Laravel 12 + Vue3 的免费可商用企业级后台系统,支持前后端分离。内置权限管理、动态路由、代码生成、插件系统(直连 Composer)、Excel 导入导出、SFC 远程加载等核心能力,开箱即用,模块化设计,助力快速构建 CMS/CRM/OA 等系统。(239字)
436 5
Laravel12 + Vue3 的免费可商用商业级管理后台 CatchAdmin V5 正式发布
|
存储 人工智能 弹性计算
2025年阿里云企业高性能云服务器租用价格与选型详解
随着企业数字化转型,阿里云于2025年推出多款高性能云服务器实例,涵盖计算、通用和内存密集型场景。文章分析了企业选择云服务器的核心要点,包括明确业务需求(如计算密集型任务推荐计算型实例)、性能与架构升级(如第八代实例性能提升20%),以及第九代实例支持AI等高算力需求。同时提供了配置价格参考和成本优化策略,助力企业实现效率与成本的最优平衡。
|
JSON 安全 应用服务中间件
【使用必读】服务端集成网易云信IM 即时通讯-回调说明篇(一)
【使用必读】服务端集成网易云信IM 即时通讯-回调说明篇(一)
822 0
|
数据可视化 JavaScript 前端开发
低代码可视化Uniapp点击事件-代码生成器
低代码可视化Uniapp点击事件-代码生成器
450 0
低代码可视化Uniapp点击事件-代码生成器
|
JavaScript 前端开发 API
vue如何解决跨域?
vue如何解决跨域?
329 0
|
存储 编解码 缓存
视频服务器配置参数有哪些要求和标准
视频服务器配置参数有哪些要求和标准
|
存储 人工智能 自然语言处理
云原生向量数据库Milvus(一)-简述、系统架构及应用场景(上)
Milvus 是一款云原生向量数据库,它具备高可用、高性能、易拓展的特点,用于海量向量数据的实时召回。