Android ROOM数据库 多表查询出现数据错乱或重复的问题修复-kotlin

Android ROOM数据库 多表查询出现数据错乱或重复的问题修复-kotlin

前言

关于多表查询,之前我写过一篇文章介绍,Android Room 数据库使用@Relation注解进行多表查询-Kotlin,是基于官方的描述来写的,一直没有机会在项目中使用,但是最近使用的时候才发现了它的问题,当关系表中增加一个标记,就会出现查询的数据不正确的问题;

说明

假设一个音乐类APP,首先有账户系统,也就是有个用户UserInfo的表,然后有歌单GroupInfo的表,歌曲SongInfo的表,有个歌单与歌曲的关系表

/**
 * 用户信息
 * @Author: D10NG
 * @Time: 2021/6/3 3:28 下午
 */
@Entity
data class UserInfo(
    @PrimaryKey
    var userId: Long = 0,

    var name: String = ""
): Serializable

/**
 * 歌单
 * @Author: D10NG
 * @Time: 2021/6/3 3:32 下午
 */
@Entity(
    primaryKeys = ["groupId", "userId"]
)
data class GroupInfo(
    var groupId: Long = 0,

    var userId: Long = 0,

    var name: String = "",
): Serializable
/**
 * 歌曲
 * @Author: D10NG
 * @Time: 2021/6/3 3:35 下午
 */
@Entity(
    primaryKeys = ["songId", "userId"]
)
data class SongInfo(
    var songId: Long = 0,

    var userId: Long = 0,

    var name: String = ""
): Serializable

/**
 * 歌单与歌的关系
 * @Author: D10NG
 * @Time: 2021/6/3 3:44 下午
 */
@Entity(
    primaryKeys = ["userId", "groupId", "songId"],
    foreignKeys = [ForeignKey(entity = GroupInfo::class, parentColumns = ["groupId", "userId"], childColumns = ["groupId", "userId"], onDelete = ForeignKey.CASCADE)]
)
data class GroupWithSongRelation(
    var userId: Long = 0,
    var groupId: Long = 0,
    var songId: Long = 0
): Serializable

然后数据库插入关系数据

// 用户0,歌单0,有歌曲0
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 0, 0))
// 用户0,歌单1,有歌曲0,1
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 1, 0))
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 1, 1))
// 用户0,歌单2,有歌曲0,1,2
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 2, 0))
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 2, 1))
db.getGroupWithSongDao().insert(GroupWithSongRelation(0, 2, 2))

// 用户1,歌单0,有歌曲1
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 0, 1))
// 用户1,歌单1,有歌曲1,2
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 1, 1))
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 1, 2))
// 用户1,歌单2,有歌曲1,2,3
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 2, 1))
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 2, 2))
db.getGroupWithSongDao().insert(GroupWithSongRelation(1, 2, 3))

编写查询语句

    // 查询歌单带歌曲信息
    @Transaction
    @Query("SELECT * FROM groupinfo WHERE userId = (:userId) AND groupId = (:groupId)")
    suspend fun susQueryGroup(userId: Long, groupId: Long): GroupWithSongData?

查询 用户0 歌单1 的结果为:
在这里插入图片描述
很明显可以看到数据不但重复了,还把属于用户1的歌单给混进来了

解决

直接使用JOIN语句进行查询

    @Query("SELECT * FROM songinfo JOIN (SELECT * FROM groupwithsongrelation WHERE userId = :userId AND groupId = :groupId) groupwithsongrelation ON groupwithsongrelation.songId = SongInfo.songId WHERE SongInfo.userId=:userId")
    suspend fun susQueryGroupSong(userId: Long, groupId: Long): List<SongInfo>

JOIN语句中先做一个子查询,把关键数据找出来先
接着,还得在查询结果中增加一个WHERE,将重复数据排除掉

查询结果:
在这里插入图片描述

Github

工程DEMO:
https://github.com/D10NGYANG/RoomDemo

完事

Kotlin 是一种运行在 JVM 上的静态类型编程语言,它兼容 Java 代码,也被设计用于 Android 开发。Room 是一个数据库持久化库,它是 Android Architecture Components 的一部分,提供了更加便捷的方式来访问 SQLite 数据库。在 Kotlin 中使用 Room 数据库进行数据持久化,通常包括以下几个步骤: 1. 定义实体(Entity):通过注解来定义数据库中的表。例如,使用 `@Entity` 注解来标记一个类表示数据库中的一个表。 2. 创建数据库访问对象(DAO):使用注解定义访问数据库的方法。例如,使用 `@Dao` 注解标记一个接口或抽象类,并在其中定义对数据库进行增删改查(CRUD)操作的方法。 3. 定义数据库(Database):创建一个抽象类并使用 `@Database` 注解来标记,该注解需要包含数据库版本号和所有实体类列表。这个类还需要提供 DAO 的访问接口。 4. 配置数据库构建器:在应用的模块级 build.gradle 文件中添加 Room 运行时库依赖,并使用 `@Database` 注解的抽象类实例化一个 Room 数据库对象。 下面是一个简单的示例来说明这个过程: ```kotlin // 1. 定义实体类 @Entity data class User( @PrimaryKey val id: Int, @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? ) // 2. 创建 DAO @Dao interface UserDao { @Insert suspend fun insertUser(user: User) @Query("SELECT * FROM user") fun getAllUsers(): Flow<List<User>> } // 3. 定义数据库 @Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao } // 4. 在应用中配置 Room val db = Room.databaseBuilder( applicationContext, AppDatabase::class.java, "database-name" ).build() ``` 在上述代码中,`User` 是一个实体类,它代表了数据库中的一个表。`UserDao` 是一个 DAO 接口,其中包含了对用户表进行操作的方法。`AppDatabase` 是数据库的抽象类定义,它继承自 `RoomDatabase`,并提供了访问 DAO 的方法。最后,我们使用 `Room.databaseBuilder()` 创建了数据库实例。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值