Definiowanie relacji „wiele do wielu” i wyszukiwanie ich

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:

  1. Zdefiniuj relację: utwórz encje i encję asocjacyjną (tabelę odniesień krzyżowych), aby reprezentować relację wiele do wielu.
  2. 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 Playlist i listę wszystkich obiektów Song uwzglę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 Song i listę wszystkich obiektów Playlist, 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 obiekty PlaylistWithSongs.
  • getSongsWithPlaylists: ta metoda wysyła zapytanie do bazy danych i zwraca wszystkie obiekty SongWithPlaylists.

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