Menentukan dan membuat kueri hubungan bertingkat

Terkadang, Anda mungkin perlu membuat kueri kumpulan tiga tabel atau lebih yang semuanya saling berkaitan. Dalam hal ini, Anda menentukan hubungan bertingkat antara tabel.

Misalkan dalam contoh aplikasi streaming musik, Anda ingin membuat kueri semua pengguna, semua playlist untuk setiap pengguna, dan semua lagu di setiap playlist untuk setiap pengguna. Pengguna memiliki hubungan one-to-many dengan playlist, dan playlist memiliki hubungan many-to-many dengan lagu. Contoh kode berikut menunjukkan class yang mewakili entity ini, serta tabel referensi silang untuk hubungan many-to-many antara playlist dan lagu:

@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"], indices = [Index("playlistId", "songId")])
data class PlaylistSongCrossRef(
    val playlistId: Long,
    val songId: Long
)

Pertama, buat model hubungan antara dua tabel dalam kumpulan seperti yang biasa Anda lakukan, menggunakan class data dan anotasi @Relation. Contoh berikut menunjukkan class PlaylistWithSongs yang memodelkan hubungan many-to-many antara class entity Playlist dan class entity Song:

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

Setelah Anda menentukan class data yang merepresentasikan hubungan ini, buat class data lain yang memodelkan hubungan antara tabel lain dari kumpulan dan class hubungan pertama, "menyarangkan" hubungan yang ada ke dalam hubungan yang baru. Contoh berikut menunjukkan class UserWithPlaylistsAndSongs yang memodelkan hubungan one-to-many di antara class entity User dan class hubungan PlaylistWithSongs:

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

Class UserWithPlaylistsAndSongs secara tidak langsung memodelkan hubungan antara ketiga class entity: User, Playlist, dan Song. Hal ini diilustrasikan dalam gambar 1.

UserWithPlaylistsAndSongs memodelkan hubungan antara User dan
  PlaylistWithSongs, yang kemudian memodelkan hubungan antara Playlist
  dan Song.
Gambar 1. Diagram hubungan class dalam contoh aplikasi streaming musik.

Jika kumpulan Anda memiliki lebih banyak tabel, buat class untuk memodelkan hubungan antara setiap tabel yang tersisa dan class hubungan sebelumnya. Proses ini akan membuat rantai hubungan bertingkat di antara semua tabel yang ingin Anda kueri.

Terakhir, tambahkan fungsi ke class objek akses data (DAO) untuk menampilkan fungsi kueri yang diperlukan aplikasi Anda. Fungsi ini memerlukan Room untuk menjalankan beberapa kueri, jadi tambahkan anotasi @Transaction sehingga seluruh operasi dijalankan secara atomik:

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