巢狀關係

有時候,您可能需要查詢三組以上彼此相關的資料表。如果是這種情況,您可以定義資料表之間的「巢狀結構關係」

在音樂串流應用程式範例中,假設您想查詢所有使用者、每位使用者的所有播放清單,以及每位使用者的每個播放清單中的所有歌曲。使用者與播放清單之間具有一對多關係,而播放清單與歌曲之間則有多對多關係。以下程式碼範例顯示代表這些實體的類別,以及播放清單與歌曲之間多對多關係的交叉參照資料表:

Kotlin

@Entity
data class User(
    @PrimaryKey val userId: Long,
    val name: String,
    val age: Int
)

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userCreatorId: Long,
    val playlistName: String
)

@Entity
data class Song(
    @PrimaryKey val songId: Long,
    val songName: String,
    val artist: String
)

@Entity(primaryKeys = ["playlistId", "songId"])
data class PlaylistSongCrossRef(
    val playlistId: Long,
    val songId: Long
)

Java

@Entity
public class User {
    @PrimaryKey public long userId;
    public String name;
    public int age;
}

@Entity
public class Playlist {
    @PrimaryKey public long playlistId;
    public long userCreatorId;
    public String playlistName;
}
@Entity
public class Song {
    @PrimaryKey public long songId;
    public String songName;
    public String artist;
}

@Entity(primaryKeys = {"playlistId", "songId"})
public class PlaylistSongCrossRef {
    public long playlistId;
    public long songId;
}

首先,請按照平常的方法,使用資料類別和 @Relation 註解,為資料集內的兩個資料表建立關係模型。以下範例顯示的 PlaylistWithSongs 類別能夠建立 Playlist 實體類別與 Song 實體類別之間的多對多關係模型:

Kotlin

data class PlaylistWithSongs(
    @Embedded val playlist: Playlist,
    @Relation(
         parentColumn = "playlistId",
         entityColumn = "songId",
         associateBy = Junction(PlaylistSongCrossRef::class)
    )
    val songs: List<Song>
)

Java

public class PlaylistWithSongs {
    @Embedded public Playlist playlist;
    @Relation(
         parentColumn = "playlistId",
         entityColumn = "songId",
         associateBy = Junction(PlaylistSongCrossRef.class)
    )
    public List<Song> songs;
}

定義代表這個關係的資料類別後,請建立另一個資料類別,為資料集中的另一個資料表和第一個關係類別建立關係模型,也就是在新關係內建立「巢狀結構」的現有關係。以下範例顯示的 UserWithPlaylistsAndSongs 類別能夠建立 User 實體類別和 PlaylistWithSongs 關係類別之間的一對多關係模型:

Kotlin

data class UserWithPlaylistsAndSongs(
    @Embedded val user: User
    @Relation(
        entity = Playlist::class,
        parentColumn = "userId",
        entityColumn = "userCreatorId"
    )
    val playlists: List<PlaylistWithSongs>
)

Java

public class UserWithPlaylistsAndSongs {
    @Embedded public User user;
    @Relation(
        entity = Playlist.class,
        parentColumn = "userId",
        entityColumn = "userCreatorId"
    )
    public List<PlaylistWithSongs> playlists;
}

UserWithPlaylistsAndSongs 類別間接建立 UserPlaylistSong 這三種實體類別之間的關係模型,如圖 1 所示。

UserWithplaylistAndSongs 建立了 User 和 PlaylistWithSongs 之間的關係模型,進而建立 Playlist 和 Song 之間的關係模型。
圖 1. 音樂串流應用程式範例中的關係類別圖。

如果資料集中還有更多資料表,請建立類別來為每個剩餘的資料表與關係類別之間建立關係模型,而該關係類別會在所有先前資料表之間建立關係模型。這項操作會在您要查詢的所有資料表之間建立巢狀結構關係鏈結。

最後,在 DAO 類別中新增方法,以顯示應用程式所需的查詢函式。此方法會要求 Room 執行多項查詢,因此請在此方法中加入 @Transaction 註解,讓整個作業以不可中斷的方式執行:

Kotlin

@Transaction
@Query("SELECT * FROM User")
fun getUsersWithPlaylistsAndSongs(): List<UserWithPlaylistsAndSongs>

Java

@Transaction
@Query("SELECT * FROM User")
public List<UserWithPlaylistsAndSongs> getUsersWithPlaylistsAndSongs();