Relacja wiele do wielu między 2 encjami to relacja, w której każda instancja encji nadrzędnej odpowiada 0 lub większej liczbie instancji encji podrzędnej i odwrotnie.
W przykładzie aplikacji do odtwarzania strumieniowego muzyki rozważmy utwory 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 encją Playlist a encją Song występuje relacja wiele do wielu.
Aby zdefiniować relacje wiele do wielu w bazie danych i wysyłać do niej zapytania:
- Zdefiniuj relację: utwórz encje i encję asocjacyjną (tabelę odniesień krzyżowych), aby reprezentować relację wiele do wielu.
- Wysyłaj zapytania o encje: określ, jak chcesz wysyłać zapytania o powiązane encje, i utwórz klasy danych, które będą reprezentować zamierzone dane wyjściowe.
Zdefiniuj relację
Aby zdefiniować relację wiele do wielu, najpierw utwórz klasę dla każdej z 2 encji. Relacje wiele do wielu różnią się od innych typów relacji tym, że w encji podrzędnej zwykle nie ma odniesienia do encji nadrzędnej. Zamiast tego utwórz trzecią klasę, która będzie reprezentować encję asocjacyjną lub tabelę odniesień krzyżowych między 2 encjami.
Tabela odniesień krzyżowych musi zawierać kolumny klucza podstawowego z każdej encji w relacji wiele do wielu reprezentowanej w tabeli. W tym przykładzie każdy wiersz w tabeli odniesień krzyżowych odpowiada parze instancji Playlist i instancji Song, w której utwór, do którego się odwołujesz, jest uwzględniony na playliście, do której się odwołujesz.
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;
}
Wysyłanie zapytań o encje
Następny krok zależy od tego, jak chcesz wysyłać zapytania o te powiązane encje.
- Jeśli chcesz wysyłać zapytania o playlisty i listę odpowiadających im utworów , utwórz nową klasę danych, która zawiera pojedynczy obiekt
Playlisti listę wszystkich obiektówSonguwzględnionych na playliście. - Jeśli chcesz wysyłać zapytania o utwory i listę odpowiadających im playlist , utwórz nową klasę danych, która zawiera pojedynczy obiekt
Songi listę wszystkich obiektówPlaylist, na których znajduje się utwór.
W obu przypadkach modeluj relację między encjami za pomocą właściwości
associateBy w adnotacji @Relation w każdej z tych
klas, aby zidentyfikować encję odniesień krzyżowych, która zapewnia relację
między encją Playlist a encją 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 będzie udostępniać funkcję zapytania potrzebną Twojej 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.
Każda z tych metod wymaga, aby biblioteka Room uruchomiła 2 zapytania, dlatego dodaj do obu metod adnotację
@Transaction, aby cała
operacja była wykonywana atomowo.
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();