m:n-Beziehungen definieren und abfragen

Eine m:n-Beziehung zwischen zwei Entitäten ist eine Beziehung, bei der jede Instanz der übergeordneten Entität null oder mehr Instanzen der untergeordneten Entität entspricht und umgekehrt.

Betrachten Sie im Beispiel der Musikstreaming-App die Songs in den nutzerdefinierten Playlists. Jede Playlist kann viele Songs enthalten und jeder Song kann Teil vieler verschiedener Playlists sein. Daher besteht eine m:n-Beziehung zwischen der Entität Playlist und der Entität Song.

So definieren und fragen Sie m:n-Beziehungen in Ihrer Datenbank ab:

  1. Beziehung definieren: Erstellen Sie die Entitäten und die assoziative Entität (Verweistabelle), um die m:n- Beziehung darzustellen.
  2. Entitäten abfragen: Legen Sie fest, wie Sie die verknüpften Entitäten abfragen möchten, und erstellen Sie Datenklassen, um die gewünschte Ausgabe darzustellen.

Beziehung definieren

Um eine m:n-Beziehung zu definieren, erstellen Sie zuerst eine Klasse für jede Ihrer beiden Entitäten. M:n-Beziehungen unterscheiden sich von anderen Beziehungstypen, da es in der untergeordneten Entität in der Regel keinen Verweis auf die übergeordnete Entität gibt. Erstellen Sie stattdessen eine dritte Klasse, um eine assoziative Entität oder Verweistabelle zwischen den beiden Entitäten darzustellen. Die Verweistabelle muss Spalten für den Primärschlüssel aus jeder Entität in der m:n-Beziehung haben, die in der Tabelle dargestellt wird. In diesem Beispiel entspricht jede Zeile in der Verweistabelle einer Paarung einer Playlist-Instanz und einer Song-Instanz, wobei der referenzierte Song in der referenzierten Playlist enthalten ist.

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

Entitäten abfragen

Der nächste Schritt hängt davon ab, wie Sie diese verknüpften Entitäten abfragen möchten.

  • Wenn Sie Playlists und eine Liste der entsprechenden Songs für jede Playlist abfragen möchten, erstellen Sie eine neue Datenklasse, die ein einzelnes Playlist-Objekt und eine Liste aller Song-Objekte enthält, die in der Playlist enthalten sind.
  • Wenn Sie Songs und eine Liste der entsprechenden Playlists für jeden Song abfragen möchten, erstellen Sie eine neue Datenklasse, die ein einzelnes Song-Objekt und eine Liste aller Playlist-Objekte enthält, in denen der Song enthalten ist.

Modellieren Sie in beiden Fällen die Beziehung zwischen den Entitäten mit der associateBy Property in der @Relation Annotation in jeder dieser Klassen, um die Verweisentität zu identifizieren, die die Beziehung zwischen der Playlist Entität und der Song Entität bereitstellt.

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

Fügen Sie der DAO-Klasse schließlich eine Methode hinzu, um die Abfragefunktion verfügbar zu machen, die Ihre App benötigt.

  • getPlaylistsWithSongs: Diese Methode fragt die Datenbank ab und gibt alle resultierenden PlaylistWithSongs-Objekte zurück.
  • getSongsWithPlaylists: Diese Methode fragt die Datenbank ab und gibt alle resultierenden SongWithPlaylists-Objekte zurück.

Für diese Methoden muss Room jeweils zwei Abfragen ausführen. Fügen Sie daher beiden Methoden die @Transaction Annotation hinzu, damit der gesamte Vorgang atomar ausgeführt wird.

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