Em ums relação de muitos para muitos entre duas entidades, cada instância da entidade pai corresponde a zero ou mais instâncias da entidade filha. O inverso também é verdadeiro.
No exemplo do app de streaming de música, considere as músicas nas playlists
definidas pelo usuário. Cada playlist pode incluir muitas músicas, e cada música pode fazer parte de
muitas playlists diferentes. Portanto, há uma relação de muitos para muitos
entre a entidade Playlist
e a entidade Song
.
Siga estas etapas para definir e consultar relações "muitos para muitos" no seu banco de dados:
- Definir a relação: estabeleça as entidades e a entidade associativa (tabela de referência cruzada) para representar a relação de muitos para muitos.
- Consultar as entidades: determine como você quer consultar as entidades relacionadas e crie classes de dados para representar a saída pretendida.
Definir a relação
Para definir uma relação de muitos para muitos, crie uma classe para cada
entidade. As relações de muitos para muitos são diferentes de outros tipos de relacionamento
porque geralmente não há referência à entidade mãe na entidade
filha. Em vez disso, crie uma terceira classe para representar uma entidade
associativa (link em inglês) ou uma tabela de referência cruzada (link em inglês) entre as duas entidades.
A tabela de referência cruzada precisa ter colunas para a chave primária de cada entidade
na relação de muitos para muitos representada na tabela. Neste exemplo, cada
linha na tabela de referência cruzada corresponde a um par de uma instância Playlist
e uma instância Song
em que a música referenciada está incluída na
playlist referenciada.
Kotlin
@Entity
data class Playlist(
@PrimaryKey val playlistId: 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 Playlist {
@PrimaryKey public long playlistId;
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;
}
Consultar as entidades
A próxima etapa depende de como você quer consultar as entidades relacionadas.
- Caso queira consultar playlists e uma lista das músicas correspondentes em
cada playlist, crie uma nova classe de dados que contenha um único objeto
Playlist
e uma lista de todos os objetosSong
que a playlist inclui. - Se você quiser consultar músicas e uma lista das playlists correspondentes para
cada uma, crie uma nova classe de dados que contenha um único objeto
Song
e uma lista de todos os objetosPlaylist
em que a música está incluída.
Nos dois casos, modele a relação entre as entidades usando a
propriedade associateBy
na anotação @Relation
em cada uma dessas
classes para identificar a entidade de referência cruzada que fornece a relação
entre as entidades Playlist
e Song
.
Kotlin
data class PlaylistWithSongs(
@Embedded val playlist: Playlist,
@Relation(
parentColumn = "playlistId",
entityColumn = "songId",
associateBy = Junction(PlaylistSongCrossRef::class)
)
val songs: List<Song>
)
data class SongWithPlaylists(
@Embedded val song: Song,
@Relation(
parentColumn = "songId",
entityColumn = "playlistId",
associateBy = Junction(PlaylistSongCrossRef::class)
)
val playlists: List<Playlist>
)
Java
public class PlaylistWithSongs {
@Embedded public Playlist playlist;
@Relation(
parentColumn = "playlistId",
entityColumn = "songId",
associateBy = @Junction(PlaylistSongCrossref.class)
)
public List<Song> songs;
}
public class SongWithPlaylists {
@Embedded public Song song;
@Relation(
parentColumn = "songId",
entityColumn = "playlistId",
associateBy = @Junction(PlaylistSongCrossref.class)
)
public List<Playlist> playlists;
}
Por fim, adicione um método à classe DAO para expor a função de consulta de que o app precisa.
getPlaylistsWithSongs
: esse método consulta o banco de dados e retorna todos os objetosPlaylistWithSongs
resultantes.getSongsWithPlaylists
: esse método consulta o banco de dados e retorna todos os objetosSongWithPlaylists
resultantes.
Ambos métodos exigem que o Room execute duas consultas. Portanto, adicione a
anotação @Transaction
aos dois métodos para garantir que toda a
operação seja realizada atomicamente.
Kotlin
@Transaction
@Query("SELECT * FROM Playlist")
fun getPlaylistsWithSongs(): List<PlaylistWithSongs>
@Transaction
@Query("SELECT * FROM Song")
fun getSongsWithPlaylists(): List<SongWithPlaylists>
Java
@Transaction
@Query("SELECT * FROM Playlist")
public List<PlaylistWithSongs> getPlaylistsWithSongs();
@Transaction
@Query("SELECT * FROM Song")
public List<SongWithPlaylists> getSongsWithPlaylists();