กําหนดและค้นหาความสัมพันธ์แบบหลายต่อหลาย

ความสัมพันธ์แบบหลายต่อหลายระหว่าง 2 เอนทิตีคือความสัมพันธ์ที่แต่ละอินสแตนซ์ของเอนทิตีหลักสอดคล้องกับอินสแตนซ์ของเอนทิตีย่อยตั้งแต่ 0 รายการขึ้นไป และในทางกลับกันก็เป็นเช่นเดียวกัน

ในตัวอย่างแอปสตรีมมิงเพลง ให้พิจารณาเพลงในเพลย์ลิสต์ที่ผู้ใช้กำหนด เพลย์ลิสต์แต่ละรายการมีเพลงได้หลายเพลง และเพลงแต่ละเพลงก็เป็นส่วนหนึ่งของเพลย์ลิสต์ต่างๆ ได้หลายรายการ ดังนั้นจึงมีความสัมพันธ์แบบหลายต่อหลาย ระหว่างเอนทิตี Playlist กับเอนทิตี Song

ทำตามขั้นตอนต่อไปนี้เพื่อกำหนดและค้นหาความสัมพันธ์แบบหลายต่อหลายในฐานข้อมูล

  1. กำหนดความสัมพันธ์: สร้างเอนทิตีและเอนทิตีที่เชื่อมโยง (ตารางอ้างอิงโยง) เพื่อแสดงความสัมพันธ์แบบหลายต่อหลาย
  2. ค้นหาเอนทิตี: กำหนดวิธีที่ต้องการค้นหา เอนทิตีที่เกี่ยวข้องและสร้างคลาสข้อมูลเพื่อแสดงเอาต์พุตที่ต้องการ

กำหนดความสัมพันธ์

หากต้องการกำหนดความสัมพันธ์แบบหลายต่อหลาย ให้สร้างคลาสสำหรับเอนทิตีทั้ง 2 รายการก่อน ความสัมพันธ์แบบกลุ่มต่อกลุ่มแตกต่างจากความสัมพันธ์ประเภทอื่นๆ เนื่องจากโดยทั่วไปแล้วจะไม่มีการอ้างอิงถึงเอนทิตีหลักในเอนทิตีย่อย แต่ให้สร้างคลาสที่ 3 เพื่อแสดงเอนทิตีแบบเชื่อมโยงหรือตารางอ้างอิงโยงระหว่างเอนทิตี 2 รายการ ตารางการอ้างอิงโยงต้องมีคอลัมน์สำหรับคีย์หลักจากแต่ละเอนทิตี ในความสัมพันธ์แบบหลายต่อหลายที่แสดงในตาราง ในตัวอย่างนี้ แต่ละ แถวในตารางการอ้างอิงโยงจะสอดคล้องกับการจับคู่ของอินสแตนซ์ Playlist และอินสแตนซ์ Song ซึ่งมีเพลงที่อ้างอิงรวมอยู่ใน เพลย์ลิสต์ที่อ้างอิง

Kotlin

@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

Kotlin

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 เรียกใช้การค้นหา 2 รายการ ดังนั้นให้เพิ่ม คำอธิบายประกอบ @Transaction ลงในทั้ง 2 วิธีเพื่อให้ระบบดำเนินการทั้งหมด แบบอะตอม

Kotlin

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