Definire e eseguire query sulle relazioni many-to-many

Una relazione molti-a-molti tra due entità è una relazione in cui ogni istanza dell'entità principale corrisponde a zero o più istanze dell'entità secondaria e vale anche il contrario.

Nell'esempio dell'app di streaming musicale, prendi in considerazione i brani nelle playlist definite dall'utente. Ogni playlist può includere molti brani e ogni brano può far parte di molte playlist diverse. Pertanto, esiste una relazione many-to-many tra l'entità Playlist e l'entità Song.

Per definire e eseguire query sulle relazioni many-to-many nel database:

  1. Definire la relazione: stabilisci le entità e l'entità associativa (tabella di riferimento incrociato) per rappresentare la relazione many-to-many.
  2. Esegui query sulle entità: determina come eseguire query sulle entità correlate e crea classi di dati per rappresentare l'output previsto.

Definisci la relazione

Per definire una relazione molti-a-molti, crea innanzitutto un corso per ciascuna delle due entità. Le relazioni many-to-many sono diverse da altri tipi di relazioni perché in genere non esiste alcun riferimento all'entità principale nell'entità figlia. Crea invece una terza classe per rappresentare un'entità associativa o una tabella di riferimenti incrociati tra le due entità. La tabella di riferimento incrociato deve avere colonne per la chiave primaria di ogni entità nella relazione molti-a-molti rappresentata nella tabella. In questo esempio, ogni riga della tabella di riferimento corrisponde a un accoppiamento di un'istanza Playlist e un'istanza Song in cui il brano a cui si fa riferimento è incluso nella playlist a cui si fa riferimento.

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;
}

Esegui una query sulle entità

Il passaggio successivo dipende da come vuoi eseguire query su queste entità correlate.

  • Se vuoi eseguire query sulle playlist e su un elenco dei brani corrispondenti per ogni playlist, crea una nuova classe di dati contenente un singolo oggetto Playlist e un elenco di tutti gli oggetti Song inclusi nella playlist.
  • Se vuoi eseguire query sui brani e su un elenco delle playlist corrispondenti per ciascuno, crea una nuova classe di dati contenente un singolo oggetto Song e un elenco di tutti gli oggetti Playlist in cui è incluso il brano.

In entrambi i casi, modella la relazione tra le entità utilizzando la proprietà associateBy nell'annotazione @Relation in ciascuna di queste classi per identificare l'entità di riferimento incrociato che fornisce la relazione tra l'entità Playlist e l'entità 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;
}

Infine, aggiungi un metodo alla classe DAO per esporre la funzione di query di cui ha bisogno la tua app.

  • getPlaylistsWithSongs: questo metodo esegue query sul database e restituisce tutti gli oggetti PlaylistWithSongs risultanti.
  • getSongsWithPlaylists: questo metodo esegue query sul database e restituisce tutti gli oggetti SongWithPlaylists risultanti.

Questi metodi richiedono ciascuno a Room di eseguire due query, quindi aggiungi l'annotazione @Transaction a entrambi i metodi in modo che l'intera operazione venga eseguita in modo atomico.

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();