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

完事