Relacja wiele do wielu między dwoma elementami to relacja, w której każdy element nadrzędny odpowiada co najmniej 0 elementom podrzędnym, a odwrotnie.
W przypadku aplikacji do strumieniowego odtwarzania muzyki zastanów się nad utworami na playlistach zdefiniowanych przez użytkownika. Każda playlista może zawierać wiele utworów, a każdy utwór może być częścią wielu różnych playlist. Dlatego między elementem Playlist
a elementem Song
istnieje relacja „wiele do wielu”.
Aby zdefiniować relacje „wiele do wielu” w bazie danych i wysyłać do niej zapytania:
- Zdefiniuj relację: określ elementy i element skojarzeniowy (tabelę odniesień), aby reprezentować relację „wiele do wielu”.
- Wysyłanie zapytań do elementów: określ, jak chcesz wysyłać zapytania do powiązanych elementów, i utwórz klasy danych, które będą reprezentować oczekiwane dane wyjściowe.
Definiowanie relacji
Aby zdefiniować relację „wiele do wielu”, najpierw utwórz klasę dla obu tych entyfikacji. Relacje wiele–wiele różnią się od innych typów relacji, ponieważ w podrzędnym obiekcie nie ma zwykle odwołania do obiektu nadrzędnego. Zamiast tego utwórz trzecią klasę, która będzie reprezentować element skojarzeniowy lub tabelę odniesień między tymi dwoma elementami.
Tabela wzajemnych odniesień musi zawierać kolumny dla klucza podstawowego każdego elementu w relacji „wiele do wielu” reprezentowanej w tabeli. W tym przykładzie każdy wiersz w tabeli wzajemnych odniesień odpowiada parze wystąpienia Playlist
i wystąpienia Song
, w której uwzględniono odwołujący się utwór na odwołującej się playliście.
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;
}
Tworzenie zapytań dotyczących encji
Kolejny krok zależy od tego, jak chcesz zapytać o te powiązane elementy.
- Jeśli chcesz wysłać zapytanie dotyczące playlist i listy odpowiednich utworów dla każdej playlisty, utwórz nową klasę danych zawierającą jeden obiekt
Playlist
i listę wszystkich obiektówSong
, które zawiera playlista. - Jeśli chcesz zapytać o utwory i listę odpowiednich playlist dla każdego utworu, utwórz nową klasę danych zawierającą pojedynczy obiekt
Song
i listę wszystkich obiektówPlaylist
, w których znajduje się utwór.
W obu przypadkach modeluj relację między elementami za pomocą właściwości associateBy
w adnotacji @Relation
w każdej z tych klas, aby zidentyfikować element odniesienia, który zapewnia relację między elementem Playlist
a elementem 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;
}
Na koniec dodaj do klasy DAO metodę, która udostępnia funkcję zapytania potrzebną aplikacji.
getPlaylistsWithSongs
: ta metoda wysyła zapytanie do bazy danych i zwraca wszystkie obiektyPlaylistWithSongs
.getSongsWithPlaylists
: ta metoda wysyła zapytanie do bazy danych i zwraca wszystkie obiektySongWithPlaylists
.
Te metody wymagają od Room uruchomienia 2 zapytań, dlatego dodaj adnotację @Transaction
do obu metod, aby cała operacja była wykonywana jako operacja atomowa.
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();