En las relaciones de varios a varios entre dos entidades, cada instancia de la entidad principal corresponde a cero o más instancias de la entidad secundaria y viceversa.
En el ejemplo de la app de transmisión de música, imagina las canciones en las playlists definidas por el usuario. Cada playlist puede incluir muchas canciones y cada canción puede pertenecer a muchas playlists. Por lo tanto, existe una relación de varios a varios entre las entidades Playlist y Song.
Sigue estos pasos para definir y consultar relaciones de varios a varios en tu base de datos:
- Define la relación: Establece las entidades y la entidad asociativa, o tabla de referencias cruzadas, para representar la relación de varios a varios.
- Consulta las entidades: Determina cómo quieres consultar las entidades relacionadas y crea clases de datos para representar el resultado deseado.
Define la relación
Para definir una relación de varios a varios, primero crea una clase para cada una de las dos entidades. Las relaciones de varios a varios son diferentes de otros tipos de relación porque, por lo general, no hay una referencia a la entidad principal en la entidad secundaria. Entonces, crea una tercera clase para representar una
entidad asociativa (o tabla de referencias cruzadas) entre las
dos entidades. La tabla de referencias cruzadas debe tener columnas para la clave primaria de cada entidad contemplada en la relación de varios a varios que se representa en la tabla. En este ejemplo, cada fila de la tabla de referencias cruzadas corresponde a una vinculación de una instancia Playlist y una instancia Song donde la playlist a la que se hace referencia incluye la canción a la que se hace referencia.
@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 )
Consulta las entidades
El siguiente paso depende de cómo quieras consultar las entidades relacionadas.
- Si quieres consultar playlists y un listado de las canciones correspondientes por cada playlist, crea una clase de datos nueva con un objeto
Playlistúnico y un listado de los objetosSongque incluye la playlist. - Si quieres consultar canciones y un listado de las playlists correspondientes por cada canción, crea una clase de datos nueva con un objeto
Songúnico y un listado de los objetosPlaylistque incluyen la canción.
En ambos casos, modela la relación entre las entidades mediante la
associateBy propiedad en la @Relation anotación de cada una de estas
clases para identificar la entidad de la referencia cruzada que proporciona la relación
entre la entidad Playlist y la entidad 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> )
Por último, agrega una función a la clase de objeto de acceso a datos (DAO) para exponer la función de consulta que necesita la app.
getPlaylistsWithSongs- Consulta la base de datos y muestra todos los objetos
PlaylistWithSongsresultantes. getSongsWithPlaylists- Consulta la base de datos y muestra todos los objetos
SongWithPlaylistsresultantes.
Cada función requiere que Room ejecute dos consultas. Agrega la @Transaction
anotación a ambas funciones para asegurarte de que la operación se ejecute automáticamente.
@Transaction @Query("SELECT * FROM Playlist") suspend fun getPlaylistsWithSongs(): List<PlaylistWithSongs> @Transaction @Query("SELECT * FROM Song") suspend fun getSongsWithPlaylists(): List<SongWithPlaylists>
Claves compuestas
Si defines la relación con claves compuestas, especifica varias columnas en parentColumns y entityColumns de la anotación @Relation.
Si necesitas especificar columnas en Junction, usa parentColumns y entityColumns en la anotación Junction también.
En el siguiente ejemplo, Playlist tiene una clave primaria compuesta por playlistId y creatorId. La tabla de referencias cruzadas PlaylistSongCrossRef también incluye estas columnas para hacer referencia a 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> )