Связь «многие ко многим» между двумя сущностями — это связь, при которой каждому экземпляру родительской сущности соответствует ноль или более экземпляров дочерней сущности, и обратное также верно.
В примере с приложением для потоковой передачи музыки рассмотрим песни в пользовательских плейлистах. Каждый плейлист может включать множество песен, и каждая песня может быть частью множества разных плейлистов. Следовательно, существует связь «многие ко многим» между сущностью Playlist и сущностью Song .
Выполните следующие шаги, чтобы определить и запросить связи «многие ко многим» в вашей базе данных:
- Определите взаимосвязь : создайте сущности и ассоциативную сущность (таблицу перекрестных ссылок) для представления связи «многие ко многим».
- Запрос к сущностям : Определите, как вы хотите запрашивать связанные сущности, и создайте классы данных для представления желаемого результата.
Определите взаимоотношения
Для определения связи «многие ко многим» сначала создайте класс для каждой из двух ваших сущностей. Связи «многие ко многим» отличаются от других типов связей тем, что в дочерней сущности обычно нет ссылки на родительскую сущность. Вместо этого создайте третий класс, представляющий ассоциативную сущность или таблицу перекрестных ссылок между двумя сущностями. Таблица перекрестных ссылок должна содержать столбцы для первичного ключа каждой сущности в связи «многие ко многим», представленной в таблице. В этом примере каждая строка в таблице перекрестных ссылок соответствует паре экземпляра Playlist и экземпляра Song , где ссылаемая песня включена в ссылаемый плейлист.
Котлин
@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;
}
Запрос к сущностям
Следующий шаг зависит от того, как вы хотите запрашивать информацию об этих связанных сущностях.
- Если вы хотите получить список плейлистов и соответствующих им песен , создайте новый класс данных, содержащий один объект
Playlistи список всех объектовSong, которые входят в данный плейлист. - Если вы хотите получить список песен и соответствующих плейлистов для каждой из них, создайте новый класс данных, содержащий один объект
Songи список всех объектовPlaylist, в которые включена эта песня.
В любом случае, смоделируйте взаимосвязь между сущностями, используя свойство associateBy в аннотации @Relation в каждом из этих классов, чтобы определить сущность перекрестной ссылки, обеспечивающую связь между сущностью Playlist и сущностью Song .
Котлин
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;
}
Наконец, добавьте в класс DAO метод, который предоставит доступ к функции запроса, необходимой вашему приложению.
- Метод `
getPlaylistsWithSongsвыполняет запрос к базе данных и возвращает все полученные объектыPlaylistWithSongs. - Метод `
getSongsWithPlaylistsвыполняет запрос к базе данных и возвращает все полученные объектыSongWithPlaylists.
Для выполнения каждого из этих методов Room должен обрабатывать два запроса, поэтому добавьте аннотацию @Transaction к обоим методам, чтобы вся операция выполнялась атомарно.
Котлин
@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();