Une relation de type plusieurs à plusieurs entre deux entités est une relation dans laquelle chaque instance de l'entité parente correspond à zéro instance ou plus de l'entité enfant, et inversement.
Reprenons à nouveau l'exemple de l'application de streaming musical et penchons-nous sur les titres des playlists définies par l'utilisateur. Chaque playlist peut inclure de nombreux titres, et chacun d'eux peut faire partie de différentes playlists. Par conséquent, il existe une relation de type plusieurs à plusieurs entre les entités Playlist et Song.
Pour définir et interroger des relations de type plusieurs à plusieurs dans votre base de données :
- Définissez la relation : établissez les entités et l' entité associative (ou tableau de concordance) pour représenter la relation de type plusieurs à plusieurs.
- Interrogez les entités : déterminez comment vous souhaitez interroger les entités associées et créez des classes de données pour représenter la sortie prévue.
Définir la relation
Pour définir une relation de plusieurs à plusieurs, créez d'abord une classe pour chacune de vos deux entités. Les relations de type plusieurs à plusieurs se distinguent des autres types de relations, car il n'existe en général aucune référence à l'entité parente dans l'entité enfant. Créez plutôt une troisième classe pour représenter une
entité associative (ou tableau de concordance) entre les
deux entités. Le tableau de concordance doit comporter des colonnes pour la clé primaire de chaque entité dans la relation de type plusieurs à plusieurs représentée dans le tableau. Dans cet exemple, chaque ligne du tableau de concordance correspond à l'association d'une instance Playlist et d'une instance Song, où la playlist référencée inclut le titre référencé.
@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"], indices = [Index("playlistId", "songId")]) data class PlaylistSongCrossRef( val playlistId: Long, val songId: Long )
Interroger les entités
L'étape suivante dépend de la façon dont vous souhaitez interroger ces entités associées.
- Si vous souhaitez interroger des playlists et une liste des titres correspondant à chaque playlist, créez une classe de données contenant un seul objet
Playlistet une liste des objetsSonginclus dans la playlist. - Si vous souhaitez interroger des titres et une liste des playlists correspondant à chaque titre, créez une classe de données contenant un seul objet
Songet une liste des objetsPlaylistqui incluent le titre.
Dans les deux cas, représentez la relation entre les entités à l'aide de la
associateBy propriété de l'@Relation annotation dans chacune de ces
classes pour identifier l'entité de concordance déterminant la relation
entre l'entité Playlist et l'entité Song.
data class PlaylistWithSongs( @Embedded val playlist: Playlist, @Relation( parentColumns = ["playlistId"], entityColumns = ["songId"], associateBy = Junction(PlaylistSongCrossRef::class) ) val songs: List<Song> ) data class SongWithPlaylists( @Embedded val song: Song, @Relation( parentColumns = ["songId"], entityColumns = ["playlistId"], associateBy = Junction(PlaylistSongCrossRef::class) ) val playlists: List<Playlist> )
Enfin, ajoutez une fonction à la classe d'objet d'accès aux données (DAO) pour afficher la fonction de requête nécessaire à votre application.
getPlaylistsWithSongs- Interroge la base de données et renvoie tous les objets
PlaylistWithSongsobtenus. getSongsWithPlaylists- Interroge la base de données et renvoie tous les objets
SongWithPlaylistsobtenus.
Chaque fonction nécessite que Room exécute deux requêtes. Ajoutez l'@Transaction
annotation aux deux fonctions pour vous assurer que l'opération s'exécute de manière atomique.
@Transaction @Query("SELECT * FROM Playlist") suspend fun getPlaylistsWithSongs(): List<PlaylistWithSongs> @Transaction @Query("SELECT * FROM Song") suspend fun getSongsWithPlaylists(): List<SongWithPlaylists>
Clés composites
Si vous définissez la relation à l'aide de clés composites, spécifiez plusieurs colonnes dans parentColumns et entityColumns de l'annotation @Relation.
Si vous devez spécifier des colonnes dans Junction, utilisez également parentColumns et entityColumns dans l'annotation Junction.
Dans l'exemple suivant, Playlist possède une clé primaire composite composée de playlistId et creatorId. Le tableau de concordance PlaylistSongCrossRef inclut également ces colonnes pour référencer la playlist.
@Entity(primaryKeys = ["playlistId", "creatorId"]) data class Playlist( val playlistId: Long, val creatorId: Long, val playlistName: String ) @Entity data class Song( @PrimaryKey val songId: Long, val songName: String, val artist: String ) @Entity(primaryKeys = ["playlistId", "creatorId", "songId"]) data class PlaylistSongCrossRef( val playlistId: Long, val creatorId: Long, val songId: Long ) data class PlaylistWithSongs( @Embedded val playlist: Playlist, @Relation( parentColumns = ["playlistId", "creatorId"], entityColumns = ["songId"], associateBy = Junction(PlaylistSongCrossRef::class) ) val songs: List<Song> )