Definiowanie relacji „wiele do wielu” i wyszukiwanie ich

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:

  1. Zdefiniuj relację: określ elementy i element skojarzeniowy (tabelę odniesień), aby reprezentować relację „wiele do wielu”.
  2. 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ów Song, 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ów Playlist, 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 obiekty PlaylistWithSongs.
  • getSongsWithPlaylists: ta metoda wysyła zapytanie do bazy danych i zwraca wszystkie obiekty SongWithPlaylists.

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