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

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

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

@Entity
data class User(
    @PrimaryKey val userId: Long,
    val name: String,
    val age: Int
)

@Entity
data class Playlist(
    @PrimaryKey val playlistId: Long,
    val userCreatorId: 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
)

ขั้นแรก ให้สร้างโมเดลความสัมพันธ์ระหว่างตาราง 2 รายการในชุดตามที่คุณ ทำตามปกติ โดยใช้คลาสข้อมูลและคำอธิบายประกอบ @Relation ตัวอย่างต่อไปนี้แสดงคลาส PlaylistWithSongs ที่สร้างโมเดลความสัมพันธ์แบบหลายต่อหลายระหว่างคลาสเอนทิตี Playlist กับคลาสเอนทิตี Song

data class PlaylistWithSongs(
    @Embedded val playlist: Playlist,
    @Relation(
        parentColumns = ["playlistId"],
        entityColumns = ["songId"],
        associateBy = Junction(PlaylistSongCrossRef::class)
    )
    val songs: List<Song>
)

หลังจากกำหนดคลาสข้อมูลที่แสดงความสัมพันธ์นี้แล้ว ให้สร้างคลาสข้อมูลอีกคลาสหนึ่งที่สร้างโมเดลความสัมพันธ์ระหว่างตารางอื่นจากชุดกับคลาสความสัมพันธ์แรก โดย "ซ้อน" ความสัมพันธ์ที่มีอยู่ภายในความสัมพันธ์ใหม่ ตัวอย่างต่อไปนี้แสดงคลาส UserWithPlaylistsAndSongs ที่สร้างโมเดล ความสัมพันธ์แบบหนึ่งต่อหลายระหว่างคลาสเอนทิตี User กับ PlaylistWithSongs คลาสความสัมพันธ์:

data class UserWithPlaylistsAndSongs(
    @Embedded val user: User,
    @Relation(
        entity = Playlist::class,
        parentColumns = ["userId"],
        entityColumns = ["userCreatorId"]
    )
    val playlists: List<PlaylistWithSongs>
)

คลาส UserWithPlaylistsAndSongs สร้างโมเดลความสัมพันธ์ ระหว่างคลาสเอนทิตีทั้ง 3 คลาส ได้แก่ User, Playlist, และ Song โดยอ้อม ซึ่งแสดงไว้ในรูปที่ 1

UserWithPlaylistsAndSongs จะสร้างความสัมพันธ์ระหว่าง User กับ
  PlaylistWithSongs ซึ่งจะสร้างความสัมพันธ์ระหว่าง Playlist
  กับ Song อีกที
รูปที่ 1 แผนภาพคลาสความสัมพันธ์ในตัวอย่างแอปสตรีมมิงเพลง

หากชุดมีตารางมากกว่านี้ ให้สร้างคลาสเพื่อสร้างโมเดลความสัมพันธ์ระหว่างตารางที่เหลือแต่ละรายการกับคลาสความสัมพันธ์ก่อนหน้า กระบวนการนี้จะสร้างความสัมพันธ์แบบซ้อนเป็นห่วงโซ่ระหว่างตารางทั้งหมดที่คุณต้องการค้นหา

สุดท้าย ให้เพิ่มฟังก์ชันลงในคลาสออบเจ็กต์การเข้าถึงข้อมูล (DAO) เพื่อแสดงฟังก์ชันการค้นหาที่แอปต้องการ ฟังก์ชันนี้กำหนดให้ Room ต้องเรียกใช้ การค้นหาหลายรายการ ดังนั้นให้เพิ่มคำอธิบายประกอบ @Transaction เพื่อให้การดำเนินการทั้งหมด ทำงานแบบอะตอมมิก:

@Transaction
@Query("SELECT * FROM User")
suspend fun getUsersWithPlaylistsAndSongs(): List<UserWithPlaylistsAndSongs>