場合によっては、互いに関連している 3 つ以上のテーブルをクエリする必要があります。その場合、テーブル間にネストされたリレーションを定義します。
音楽ストリーミング アプリの例で、全ユーザー、各ユーザーの全プレイリスト、各ユーザーの各プレイリストの全曲をクエリするとします。ユーザーにはプレイリストとの 1 対多のリレーションがあり、プレイリストには曲との多対多のリレーションがあります。次のコード例は、これらのエンティティを表すクラスと、プレイリストと曲との多対多のリレーションを表す相互参照テーブルを示しています。
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;
}
まず、通常どおり、セットの中で 2 つのテーブル間のリレーションを、データクラスと @Relation
アノテーションを使用してモデル化します。次の例は、Playlist
エンティティ クラスと Song
エンティティ クラスとの間の多対多のリレーションをモデル化する PlaylistWithSongs
クラスを示しています。
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;
}
このリレーションを表すデータクラスを定義したら、セット内の別のテーブルと最初のリレーション クラスをモデル化する別のデータクラスを作成し、新しいリレーション内に既存のリレーションを「ネスト」します。次の例は、User
エンティティ クラスと PlaylistWithSongs
リレーション クラスとの間の 1 対多のリレーションをモデル化する UserWithPlaylistsAndSongs
クラスを示しています。
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
クラスは、3 つのエンティティ クラス User
、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();