如何通过单个DAO方法获取专辑及其关联的全部歌曲
当然可以实现!在Room中处理这种一对多的关联(一个Album对应多个Song),最简洁的方式是用@Relation注解,而不是手动写复杂的JOIN查询(虽然也能做,但注解方案更优雅)。下面是具体的实现步骤:
1. 定义嵌套数据类
首先需要创建一个用来封装Album及其关联Song的数据类,用@Embedded标记Album实体,@Relation标记关联的Song列表:
data class AlbumWithSongs( // 嵌入Album实体,Room会映射Album的所有字段 @Embedded val album: Album, // 关联Song表,指定外键关联关系 @Relation( parentColumn = "id", // Album表的主键字段 entityColumn = "albumId" // Song表中指向Album的外键字段 ) val songs: List<Song> // 当前Album对应的所有Song )
2. 编写DAO方法
接下来在DAO接口中定义查询方法,只需要查询所有Album,Room会自动帮我们关联每个Album对应的Song:
@Dao interface AlbumDao { @Query("SELECT * FROM Album") fun loadAllAlbumsWithSongs(): List<AlbumWithSongs> }
原理说明
Room的执行逻辑是:
- 先执行
SELECT * FROM Album获取所有Album记录 - 对每个Album,自动执行
SELECT * FROM Song WHERE albumId = :albumId查询对应的Song - 最后将Album和它的Song列表组装成
AlbumWithSongs对象返回
可选:过滤特定Album
如果需要获取某个Artist的所有Album及其Song,只需要修改查询条件即可:
@Query("SELECT * FROM Album WHERE artistId = :artistId") fun loadAlbumsWithSongsByArtist(artistId: Int): List<AlbumWithSongs>
关于手动JOIN的补充
如果一定要用JOIN的方式,你需要自己处理结果分组(因为JOIN会返回重复的Album记录,每个Song对应一条),比如:
// 先定义一个临时的组合类 data class AlbumAndSongRaw( @Embedded val album: Album, @Embedded val song: Song? ) @Dao interface AlbumDao { @Query("SELECT * FROM Album a LEFT JOIN Song s ON a.id = s.albumId") fun loadAlbumsAndSongsRaw(): List<AlbumAndSongRaw> } // 然后在代码中手动分组 fun getAlbumsWithSongs(): List<AlbumWithSongs> { val rawList = albumDao.loadAlbumsAndSongsRaw() return rawList.groupBy { it.album } .map { (album, songEntries) -> AlbumWithSongs(album, songEntries.mapNotNull { it.song }) } }
但这种方式需要额外的分组逻辑,不如@Relation方案简洁高效。
内容的提问来源于stack exchange,提问作者Ridcully
相关产品推荐
相关产品推荐

