Android Jetpack架构组件-Room数据库查询艺术

在这里插入图片描述

一、Room 中的数据库关系查询

设计一个关系型数据库很重要的一部分是将数据拆分成具有相关关系的数据表,然后将数据以符合这种关系的逻辑方式整合到一起。从 Room 2.2 的稳定版开始,我们可利用一个 @Relation 注解来支持表之间所有可能出现的关系: 一对一、一对多和多对多。

1.1、 一对一关系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UIFL78YO-1585734559011)(//upload-images.jianshu.io/upload_images/7095626-bdb47d91e18a208a?imageMogr2/auto-orient/strip|imageView2/2/w/1080/format/webp)]

假设我们生活在一个每个人只能拥有一只狗,且每只狗只能有一个主人的 “悲惨世界” 中,这就是一对一关系。如果要以关系型数据库的方式来反应它的话,我们可以创建两张表: Dog 表和 Owner 表,其中 Dog 表通过 owner id 来引用 Owner 表中的数据,或者 Owner 表通过 dog id 来引用 Dog 表中的数据。

@Entity
data class Dog(
    @PrimaryKey val dogId: Long,
    val dogOwnerId: Long,
    val name: String,
    val cuteness: Int,
    val barkVolume: Int,
    val breed: String
)

@Entity
data class Owner(@PrimaryKey val ownerId: Long, val name: String)

假设我们想在一个列表中展示所有的狗和它们的主人,我们需要创建一个 DogAndOwner 类:


data class DogAndOwner(
    val owner: Owner,
    val dog: Dog
)

为了在 SQLite 中进行查询,我们需要 1) 运行两个查询: 一个获取所有的主人数据,一个获取所有的狗狗数据,2) 根据 owner id 来进行数据的关系映射。

SELECT * FROM Owner

SELECT * FROM Dog WHERE dogOwnerId IN (ownerId1, ownerId2, …)

要在 Room 中获取一个 List ,我们不需要自己去实现上面说的查询和映射,只需要使用 @Relation 注解。

在我们的示例中,由于 Dog 有了 owner 的信息,我们给 dog 变量增加 @Relation 注解,指定父级 (这里对应 Owner) 上的 ownerId 列对应 dogOwnerId:


data class DogAndOwner(
    @Embedded val owner: Owner,
    @Relation(
         parentColumn = "ownerId",
         entityColumn = "dogOwnerId"
    )
    val dog: Dog
)

现在我们的 Dao 类可被简化成:


@Transaction
@Query("SELECT * FROM Owner")

fun getDogsAndOwners(): List<DogAndOwner>

注意: 由于 Room 会默默的帮我们运行两个查询请求,因此需要增加 @Transaction 注解来确保这个行为是原子性的。

Dao
https://developer.android.google.cn/reference/androidx/room/Dao
@Transaction
https://developer.android.google.cn/reference/androidx/room/Transaction.html

1.2、 一对多关系

在这里插入图片描述

再假设,一个主人可以养多只狗狗,现在上面的关系就变成了一对多关系。我们之前定义的数据库 schema 并不需要改变,仍然使用同样的表结构,因为在 “多” 这一方的表中已经有了关联键。现在,要展示狗和主人的列表,我们需要创建一个新的类来进行建模:

data class OwnerWithDogs(
    val owner: Owner,
    val dogs: List<Dog>
)

为了避免运行两个独立的查询,我们可以在 Dog 和 Owner 中定义一对多的关系,同样,还是在 List 前增加 @Relation 注解。


data class OwnerWithDogs(
     @Embedded val owner: Owner,
     @Relation(
          parentColumn = "ownerId",
          entityColumn = "dogOwnerId"
     )
     val dogs: List<Dog>
)

现在,Dao 类又变成了这样:


@Transaction
@Query("SELECT * FROM Owner")

fun getDogsAndOwners(): List<OwnerWithDogs>

1.3、多对多关系

在这里插入图片描述

现在,继续假设我们生活在一个完美的世界中,一个人可以拥有多只狗,每只狗可以拥有多个主人。要对这个关系进行映射,之前的 Dog 和 Owner 表是不够的。由于一只狗狗可以有多个主人,我们需要在同一个 dog id 上能够匹配多个不同的 owner id。由于 dogId 是 Dog 表的主键,我们不能直接在 Dog 表中添加同样 id 的多条数据。为了解决这个问题,我们需要创建一个 associative 表 (也被称为连接表),这个表来存储 (dogId, ownerId) 的数据对。

@Entity(primaryKeys = ["dogId", "ownerId"])
data class DogOwnerCrossRef(
    val dogId: Long,
    val ownerId: Long
)

如果现在我们想要获取到所有的狗狗和主人的数据,也就是 List,仅需要编写两个 SQLite 查询,一个获取到所有的主人数据,另一个获取 Dog 和 DogOwnerCrossRef 表的连接数据。


SELECT * FROM Owner
SELECT
     Dog.dogId AS dogId,
     Dog.dogOwnerId AS dogOwnerId,
     Dog.name AS name,
     _junction.ownerId
FROM
     DogOwnerCrossRef AS _junction
INNER JOIN Dog ON (_junction.dogId = Dog.dogId)

WHERE _junction.ownerId IN (ownerId1, ownerId2, …)

要通过 Room 来实现这个功能,我们需要更新 OwnerWithDogs 数据类,并告诉 Room 要使用 DogOwnerCrossRef 这个连接表来获取 Dogs 数据。我们通过使用 Junction 引用这张表。


data class OwnerWithDogs(
    @Embedded val owner: Owner,
    @Relation(
         parentColumn = "ownerId",
         entityColumn = "dogId",
         associateBy = Junction(DogOwnerCrossRef::class)
    )
    val dogs: List<Dog>
)

在我们的 Dao 中,我们需要从 Owners 中选择并返回正确的数据类:

@Transaction
@Query("SELECT * FROM Owner")

fun getOwnersWithDogs(): List<OwnerWithDogs>

二、配合Rxjava的使用

重新定义查询User的Dao,如下所示:注意返回类型

    @Transaction
    @Query("SELECT * FROM Cheese")
    fun findAll(): Flowable<List<CheeseAndUser>>

在Activity/Fragment中的使用

        AppDatabase.get(this).cheeseAndUserDao().findAll()
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe { t -> Log.d("DATA", "Rxjava:" + t?.size) }

三、配合LiveData的使用

@Dao
interface UserDao {
  @Query("SELECT * FROM user")
  fun queryUsers(): LiveData<List<User>>
}

在Activity/Fragment中的使用

四、配合Paging框架的使用

@Dao
interface UserDao {

    @Query("select * from user order by name ")
    fun findAllUser(): DataSource.Factory<Int, User>

在ViewModel中的使用

class CheeseViewModel(app: Application) : AndroidViewModel(app) {
    val dao = AppDb.get(app).userDao()

    val allUser = dao.findAllCheese().toLiveData(
        Config(
            pageSize = 30,
            enablePlaceholders = true,
            maxSize = 200
        )
    )
}

在Activity/Fragment中的使用

    allUser.allCheese.observe(this, Observer {
           // adapter.submitList(it)
          ...
        })

五、结语

都到这里了,确定不看看实际开发中遇到的Room坑和迁移升级操作?待后续更新

本文示例代码已上传至Jetpack_Component

该仓库为演示Jetpack的组件的仓库,分别对Lifecyele、LiveData、ViewModel、Room的介绍和使用

##详细介绍文章

项目目录结构为如下

image.png

  • 6
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《Jetpack架构组件从入门到精通》.pdf 是一本介绍Android Jetpack架构组件的书籍。Jetpack是Google官方提供的一套组件库,旨在帮助开发者更轻松地构建高质量的Android应用程序。 这本书从入门到精通地介绍了Jetpack架构组件的各个方面。首先,它详细解释了Jetpack的基本概念和使用方法。读者可以学习到Jetpack的核心组件,如ViewModel、LiveData、Room和Navigation等,以及它们在构建Android应用时的作用。 此外,这本书还介绍了Jetpack架构组件的一些高级技术和最佳实践。读者可以学习到如何使用WorkManager实现后台任务,如何使用DataBinding进行数据绑定,以及如何使用Paging构建分页列表等。 除了介绍Jetpack架构组件的基本用法和高级技术,这本书还提供了一些实际应用示例和案例分析。读者可以通过参考这些示例来更好地理解和应用Jetpack架构组件。 总之,《Jetpack架构组件从入门到精通》.pdf 是一本全面而深入地介绍Jetpack架构组件的书籍。无论是初学者还是有一定经验的开发者,都可以通过阅读这本书来提升自己在Android应用开发中使用Jetpack的能力。 ### 回答2: 《Jetpack架构组件从入门到精通》.pdf 是一本关于Jetpack架构组件的学习指南。JetpackAndroid开发中一套强大而且灵活的组件集合,旨在帮助开发者更轻松地构建高质量的Android应用程序。 该PDF文件从入门到精通地介绍了Jetpack架构组件的各个方面。首先,它向读者介绍了Jetpack的概念和使用场景,以帮助读者了解为什么应该学习和使用这些组件。 接下来,该指南逐一介绍了Jetpack架构组件的不同模块,包括ViewModel、LiveData、Room、Navigation等。它详细解释了每个组件的功能和用法,并通过实际示例演示了如何在项目中使用它们。 此外,该指南还提供了一些常见的最佳实践和实用技巧,以帮助读者更好地理解和运用Jetpack架构组件。它还包含了一些常见问题和解决方案,帮助读者避免在实践中遇到的常见问题。 最后,该指南还提供了一些参考资料和进一步学习资源,以帮助读者深入学习和掌握Jetpack架构组件。 总的来说,该《Jetpack架构组件从入门到精通》.pdf提供了一个全面而详尽的学习指南,帮助读者了解和应用Jetpack架构组件,使他们能够更高效地构建高质量的Android应用程序。无论是初学者还是有经验的开发者,该指南都是一个值得阅读和参考的资源。 ### 回答3: 《Jetpack架构组件从入门到精通》.pdf 是一本介绍Android Jetpack架构组件的电子书,它有助于开发者学习和理解如何使用这些组件来构建高质量、稳定的Android应用程序。 Jetpack架构组件是由谷歌开发的一组库,旨在帮助开发者简化Android应用的开发过程。它提供了一系列的工具和组件,涵盖了各个方面,包括界面设计、数据库、网络通信、数据绑定、后台处理等。 这本电子书从入门到精通地介绍了各个组件使用方法和最佳实践。它首先详细介绍了Jetpack架构组件的核心概念和优势,让读者了解为什么要使用这些组件。 然后,电子书逐一介绍了常用的Jetpack组件,如Lifecycle、ViewModel、Room、LiveData、Navigation等。每个组件都被详细地讲解,包括其作用、使用方法和示例代码。读者可以通过跟随书中的案例来实际操作和理解这些组件使用。 除了介绍各个组件,电子书还分享了一些进阶的使用技巧和开发经验。这些技巧包括如何优化应用性能、处理异步任务、实现数据缓存等。通过这些实用的技巧,开发者可以进一步提高应用的质量和用户体验。 总的来说,《Jetpack架构组件从入门到精通》.pdf 是一本很有价值的学习资料,对于想要深入学习和掌握Jetpack架构组件的开发者来说是必不可少的参考书籍。无论是初学者还是有经验的开发者,都可以从中获得知识和技能的提升。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值