Определение и запрос отношений «многие ко многим»,Определение и запрос отношений «многие ко многим»

Связь «многие-ко-многим» между двумя объектами — это связь, в которой каждый экземпляр родительской сущности соответствует нулю или более экземплярам дочерней сущности, и обратное также верно.

В примере приложения для потоковой передачи музыки рассмотрим песни в пользовательских плейлистах. Каждый список воспроизведения может включать множество песен, и каждая песня может быть частью множества разных списков воспроизведения. Таким образом, между объектом Playlist и объектом Song существует связь «многие ко многим».

Выполните следующие шаги, чтобы определить и запросить отношения «многие ко многим» в вашей базе данных:

  1. Определите связь : установите сущности и ассоциативную сущность (таблицу перекрестных ссылок), чтобы представить связь «многие ко многим».
  2. Запрос сущностей . Определите, как вы хотите запрашивать связанные сущности, и создайте классы данных для представления предполагаемого результата.

Определите отношения

Чтобы определить связь «многие ко многим», сначала создайте класс для каждой из двух сущностей. Отношения «многие-ко-многим» отличаются от других типов отношений, поскольку в дочерней сущности обычно нет ссылки на родительскую сущность. Вместо этого создайте третий класс для представления ассоциативной сущности или таблицы перекрестных ссылок между двумя сущностями. Таблица перекрестных ссылок должна содержать столбцы для первичного ключа от каждой сущности в отношении «многие ко многим», представленном в таблице. В этом примере каждая строка в таблице перекрестных ссылок соответствует паре экземпляра 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
)

Ява

@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>
)

Ява

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>

Ява

@Transaction
@Query("SELECT * FROM Playlist")
public List<PlaylistWithSongs> getPlaylistsWithSongs();

@Transaction
@Query("SELECT * FROM Song")
public List<SongWithPlaylists> getSongsWithPlaylists();