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