ความสัมพันธ์แบบหลายต่อหลายระหว่าง 2 เอนทิตีคือความสัมพันธ์ที่แต่ละอินสแตนซ์ของเอนทิตีหลักสอดคล้องกับอินสแตนซ์ 0 รายการหรือมากกว่าของเอนทิตีรอง และในทางกลับกันก็เป็นจริงด้วย
ในตัวอย่างแอปสตรีมมิงเพลง ให้พิจารณาเพลงในเพลย์ลิสต์ที่ผู้ใช้กำหนด เพลย์ลิสต์แต่ละรายการมีเพลงได้หลายเพลง และเพลงแต่ละเพลงอาจอยู่ในเพลย์ลิสต์ได้หลายรายการ ดังนั้น จึงมีความสัมพันธ์แบบหลายต่อหลายระหว่างเอนทิตี Playlist และ Song
ทำตามขั้นตอนต่อไปนี้เพื่อกำหนดและค้นหาความสัมพันธ์แบบหลายต่อหลายในฐานข้อมูล
- กำหนดความสัมพันธ์: สร้างเอนทิตีและ เอนทิตีที่เชื่อมโยง หรือตารางการอ้างอิงโยง เพื่อแสดงความสัมพันธ์แบบหลายต่อหลาย
- ค้นหาเอนทิตี: กำหนดวิธีที่ต้องการค้นหาเอนทิตีที่เกี่ยวข้อง และสร้างคลาสข้อมูลเพื่อแสดงเอาต์พุตที่ต้องการ
กำหนดความสัมพันธ์
หากต้องการกำหนดความสัมพันธ์แบบหลายต่อหลาย ให้สร้างคลาสสำหรับเอนทิตีทั้ง 2 รายการก่อน ความสัมพันธ์แบบหลายต่อหลายแตกต่างจากความสัมพันธ์ประเภทอื่นๆ เนื่องจากโดยทั่วไปแล้วจะไม่มีการอ้างอิงถึงเอนทิตีหลักในเอนทิตีรอง แต่ให้สร้างคลาสที่ 3 เพื่อแสดงเอนทิตีที่เชื่อมโยง
หรือ ตารางการอ้างอิงโยง ระหว่าง
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"], indices = [Index("playlistId", "songId")]) data class PlaylistSongCrossRef( val playlistId: Long, val songId: Long )
ค้นหาเอนทิตี
ขั้นตอนถัดไปจะขึ้นอยู่กับวิธีที่ต้องการค้นหาเอนทิตีที่เกี่ยวข้องเหล่านี้
- หากต้องการค้นหา เพลย์ลิสต์ และรายการ เพลง ที่เกี่ยวข้องสำหรับแต่ละเพลย์ลิสต์ ให้สร้างคลาสข้อมูลใหม่ที่มีออบเจ็กต์
Playlistรายการเดียวและรายการออบเจ็กต์Songที่เพลย์ลิสต์มี - หากต้องการค้นหา เพลง และรายการ เพลย์ลิสต์ ที่เกี่ยวข้องสำหรับแต่ละเพลง ให้สร้างคลาสข้อมูลใหม่ที่มีออบเจ็กต์
Songรายการเดียวและรายการออบเจ็กต์Playlistที่มีเพลง
ไม่ว่าจะกรณีใด ให้สร้างโมเดลความสัมพันธ์ระหว่างเอนทิตีโดยใช้พร็อพเพอร์ตี้
associateByในคำอธิบายประกอบ@Relationในคลาสเหล่านี้แต่ละคลาสเพื่อระบุเอนทิตีการอ้างอิงโยงที่แสดงความสัมพันธ์ระหว่างเอนทิตีPlaylistและเอนทิตี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> )
สุดท้าย ให้เพิ่มฟังก์ชันลงในคลาสออบเจ็กต์การเข้าถึงข้อมูล (DAO) เพื่อแสดงฟังก์ชันการค้นหาที่แอปต้องการ
getPlaylistsWithSongs- ค้นหาฐานข้อมูลและแสดงผลออบเจ็กต์
PlaylistWithSongsทั้งหมด getSongsWithPlaylists- ค้นหาฐานข้อมูลและแสดงผลออบเจ็กต์
SongWithPlaylistsทั้งหมด
แต่ละฟังก์ชันต้องใช้ Room เพื่อเรียกใช้การค้นหา 2 รายการ เพิ่มคำอธิบายประกอบ @Transaction
ลงในทั้ง 2 ฟังก์ชันเพื่อให้แน่ใจว่าการดำเนินการจะทำงานแบบอะตอมมิก
@Transaction @Query("SELECT * FROM Playlist") suspend fun getPlaylistsWithSongs(): List<PlaylistWithSongs> @Transaction @Query("SELECT * FROM Song") suspend fun getSongsWithPlaylists(): List<SongWithPlaylists>
คีย์ผสม
หากกำหนดความสัมพันธ์โดยใช้คีย์ผสม ให้ระบุหลายคอลัมน์ใน parentColumns และ entityColumns ของคำอธิบายประกอบ @Relation
หากต้องการระบุคอลัมน์ใน Junction ให้ใช้ parentColumns และ entityColumns ในคำอธิบายประกอบ Junction ด้วย
ในตัวอย่างต่อไปนี้ Playlist มีคีย์หลักแบบผสมที่ประกอบด้วย playlistId และ creatorId ตารางการอ้างอิงโยง PlaylistSongCrossRef ยังมีคอลัมน์เหล่านี้เพื่ออ้างอิงเพลย์ลิสต์
@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> )