Mối quan hệ nhiều với nhiều giữa hai thực thể là mối quan hệ trong đó mỗi bản sao của thực thể mẹ tương ứng với không hoặc nhiều bản sao của thực thể con và ngược lại.
Trong ví dụ về ứng dụng phát nhạc trực tuyến, hãy xem xét các bài hát trong danh sách phát do người dùng lập ra. Mỗi danh sách phát có thể bao gồm nhiều bài hát và mỗi bài hát có thể thuộc nhiều danh sách phát. Do đó, có mối quan hệ nhiều với nhiều giữa thực thể Playlist và Song.
Hãy làm theo các bước sau để xác định và truy vấn mối quan hệ nhiều với nhiều trong cơ sở dữ liệu của bạn:
- Xác định mối quan hệ: Thiết lập các thực thể và thực thể liên kết hoặc bảng tham chiếu chéo để biểu thị mối quan hệ nhiều với nhiều.
- Truy vấn các thực thể: Xác định cách bạn muốn truy vấn các thực thể có liên quan và tạo các lớp dữ liệu để biểu thị đầu ra dự kiến.
Xác định mối quan hệ
Để xác định mối quan hệ nhiều với nhiều, trước tiên, hãy tạo một lớp cho mỗi thực thể. Mối quan hệ nhiều với nhiều khác hẳn với các loại quan hệ khác bởi vì thường không có tham chiếu đến thực thể mẹ trong thực thể con. Thay vào đó, hãy tạo một lớp thứ ba để đại diện cho một thực thể liên kết hoặc bảng tham chiếu chéo giữa hai thực thể. Bảng tham chiếu chéo phải có các cột cho khoá chính từ mỗi thực thể trong mối quan hệ nhiều với nhiều được thể hiện trong bảng. Trong ví dụ này, mỗi hàng trong bảng tham chiếu chéo tương ứng với một cặp gồm bản sao Playlist và bản sao Song trong đó danh sách phát được tham chiếu sẽ bao gồm bài hát được tham chiếu.
@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 )
Truy vấn các thực thể
Bước tiếp theo phụ thuộc vào cách bạn muốn truy vấn các thực thể liên quan này.
- Nếu bạn muốn truy vấn danh sách phát và danh sách bài hát tương ứng với từng danh sách phát, hãy tạo một lớp dữ liệu mới chứa một đối tượng
Playlistvà danh sách các đối tượngSongmà danh sách phát chứa. - Nếu bạn muốn truy vấn bài hát và danh sách danh sách phát tương ứng với từng bài hát, hãy tạo một lớp dữ liệu mới chứa một đối tượng
Songduy nhất và danh sách các đối tượngPlaylistchứa bài hát.
Trong cả hai trường hợp, hãy mô hình hoá mối quan hệ giữa các thực thể bằng cách sử dụng thuộc tính associateBy trong chú thích @Relation của từng lớp này để xác định thực thể tham chiếu chéo cung cấp mối quan hệ giữa thực thể Playlist và thực thể 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> )
Cuối cùng, hãy thêm một hàm vào lớp đối tượng truy cập dữ liệu (DAO) để hiển thị hàm truy vấn mà ứng dụng của bạn cần.
getPlaylistsWithSongs- Truy vấn cơ sở dữ liệu và trả về tất cả các đối tượng
PlaylistWithSongsthu được. getSongsWithPlaylists- Truy vấn cơ sở dữ liệu và trả về tất cả đối tượng
SongWithPlayliststhu được.
Mỗi hàm đều yêu cầu Room chạy hai truy vấn. Thêm chú giải @Transaction vào cả hai hàm để đảm bảo thao tác chạy một cách tỷ mỷ.
@Transaction @Query("SELECT * FROM Playlist") suspend fun getPlaylistsWithSongs(): List<PlaylistWithSongs> @Transaction @Query("SELECT * FROM Song") suspend fun getSongsWithPlaylists(): List<SongWithPlaylists>
Khoá kết hợp
Nếu bạn xác định mối quan hệ bằng khoá kết hợp, hãy chỉ định nhiều cột trong parentColumns và entityColumns của chú thích @Relation.
Nếu bạn cần chỉ định các cột trong Junction, hãy sử dụng parentColumns và entityColumns trong chú thích Junction.
Trong ví dụ sau, Playlist có một khoá chính kết hợp bao gồm playlistId và creatorId. Bảng tham chiếu chéo PlaylistSongCrossRef cũng có các cột này để tham chiếu đến danh sách phát.
@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> )