Иногда вам может понадобиться запросить набор из трех или более таблиц, связанных друг с другом. В этом случае вы определяете вложенные отношения между таблицами.
Предположим, что в примере с приложением для потоковой передачи музыки вы хотите запросить всех пользователей, все плейлисты для каждого пользователя и все песни в каждом плейлисте для каждого пользователя. У пользователей с плейлистами отношения "один ко многим", а у плейлистов с песнями – "многие ко многим". В следующем примере кода показаны классы, представляющие эти объекты, а также таблица перекрестных ссылок для отношения "многие ко многим" между плейлистами и песнями:
@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 )
Сначала смоделируйте связь между двумя таблицами из набора, как вы обычно это делаете, используя класс данных и аннотацию @Relation. В следующем примере показан класс PlaylistWithSongs, который моделирует связь "многие ко многим" между классами объектов Playlist и Song:
data class PlaylistWithSongs( @Embedded val playlist: Playlist, @Relation( parentColumns = ["playlistId"], entityColumns = ["songId"], associateBy = Junction(PlaylistSongCrossRef::class) ) val songs: List<Song> )
Определив класс данных, представляющий эту связь, создайте ещё один класс данных, который моделирует связь между другой таблицей из вашего набора и первым классом связи, "вложив" существующую связь в новую. В примере ниже показан класс UserWithPlaylistsAndSongs, который моделирует связь "один ко многим" между классом объектов User и классом связей PlaylistWithSongs:
data class UserWithPlaylistsAndSongs( @Embedded val user: User, @Relation( entity = Playlist::class, parentColumns = ["userId"], entityColumns = ["userCreatorId"] ) val playlists: List<PlaylistWithSongs> )
Класс UserWithPlaylistsAndSongs косвенно моделирует отношения между всеми тремя классами объектов: User, Playlist и Song. Это показано на рисунке 1.
Если в наборе больше таблиц, создайте класс для моделирования связи между каждой оставшейся таблицей и предыдущим классом связи. В результате этого процесса создается цепочка вложенных связей между всеми таблицами, к которым вы хотите отправить запрос.
Наконец, добавьте в класс объекта доступа к данным (DAO) функцию, которая будет предоставлять доступ к функции запроса, необходимой вашему приложению. Эта функция требует, чтобы Room выполнял несколько запросов, поэтому добавьте аннотацию @Transaction, чтобы вся операция выполнялась атомарно:
@Transaction @Query("SELECT * FROM User") suspend fun getUsersWithPlaylistsAndSongs(): List<UserWithPlaylistsAndSongs>