Às vezes, pode ser necessário consultar um conjunto de três ou mais tabelas relacionadas entre si. Nesse caso, é preciso definir relações aninhadas entre as tabelas.
Suponha que, no exemplo do app de streaming de música, você queira consultar todos os usuários, todas as playlists de cada usuário e todas as músicas em cada playlist de cada usuário. Usuários têm uma relação de um para muitos com playlists, e listas de reprodução têm uma relação de muitos para muitos com músicas. O exemplo de código abaixo mostra as classes que representam essas entidades e também a tabela de referência cruzada para a relação de muitos para muitos entre playlist e músicas:
@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 )
Primeiro, modele a relação entre duas tabelas no seu conjunto como você
faria normalmente, com uma classe de dados e a @Relation anotação. O
exemplo abaixo mostra uma classe PlaylistWithSongs que modela uma relação de muitos para muitos
entre a classe de entidade Playlist e a classe de entidade Song:
data class PlaylistWithSongs( @Embedded val playlist: Playlist, @Relation( parentColumns = ["playlistId"], entityColumns = ["songId"], associateBy = Junction(PlaylistSongCrossRef::class) ) val songs: List<Song> )
Depois de definir uma classe de dados que representa essa relação, crie outra classe que modele a relação entre outra tabela do conjunto e a classe de relação primária, "aninhando" a relação existente com a nova. O exemplo abaixo mostra uma classe UserWithPlaylistsAndSongs que modela
uma relação de um para muitos entre a classe de entidade User e a
PlaylistWithSongs classe de relação:
data class UserWithPlaylistsAndSongs( @Embedded val user: User, @Relation( entity = Playlist::class, parentColumns = ["userId"], entityColumns = ["userCreatorId"] ) val playlists: List<PlaylistWithSongs> )
A classe UserWithPlaylistsAndSongs modela indiretamente as relações
entre as três classes de entidade: User, Playlist e Song. Isso é
ilustrado na figura 1.
Se o conjunto tiver mais tabelas, crie uma classe para modelar a relação entre cada tabela restante e a classe de relação anterior. Esse processo cria uma cadeia de relações aninhadas entre todas as tabelas que você quer consultar.
Por fim, adicione uma função à classe de objeto de acesso a dados (DAO, na sigla em inglês) para expor a função de consulta que seu app precisa. Essa função exige que o Room execute
várias consultas. Portanto, adicione a anotação @Transaction para garantir que toda a
operação seja executada atomicamente:
@Transaction @Query("SELECT * FROM User") suspend fun getUsersWithPlaylistsAndSongs(): List<UserWithPlaylistsAndSongs>