You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过单个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 19:22:47