कई-से-कई रिलेशनशिप तय करना और उनसे जुड़ी क्वेरी करना

दो एंटिटी के बीच मेनी-टू-मेनी रिलेशनशिप एक ऐसा संबंध होता है जिसमें पैरंट एंटिटी का हर इंस्टेंस, चाइल्ड एंटिटी के शून्य या उससे ज़्यादा इंस्टेंस से मेल खाता है. साथ ही, इसका उल्टा भी सही होता है.

म्यूज़िक स्ट्रीमिंग ऐप्लिकेशन के उदाहरण में, उपयोगकर्ता की तय की गई प्लेलिस्ट में मौजूद गानों पर विचार करें. हर प्लेलिस्ट में कई गाने शामिल हो सकते हैं. साथ ही, हर गाना कई प्लेलिस्ट में शामिल हो सकता है. इसलिए, 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"], indices = [Index("playlistId", "songId")])
data class PlaylistSongCrossRef(
    val playlistId: Long,
    val songId: Long
)

एंटिटी के बारे में क्वेरी करना

अगला चरण इस बात पर निर्भर करता है कि आपको इन संबंधित एंटिटी के बारे में क्वेरी कैसे करनी है.

  • अगर आपको प्लेलिस्ट और हर प्लेलिस्ट के लिए, उससे जुड़े गानों की सूची के बारे में क्वेरी करनी है, तो एक नई डेटा क्लास बनाएं. इसमें एक Playlist ऑब्जेक्ट और Song ऑब्जेक्ट की सूची शामिल होनी चाहिए. इस सूची में वे गाने शामिल होने चाहिए जो प्लेलिस्ट में मौजूद हैं.
  • अगर आपको गानों और हर गाने के लिए, उससे जुड़ी प्लेलिस्ट की सूची के बारे में क्वेरी करनी है, तो एक नई डेटा क्लास बनाएं. इसमें एक Song ऑब्जेक्ट और Playlist ऑब्जेक्ट की सूची शामिल होनी चाहिए. इस सूची में वे प्लेलिस्ट शामिल होनी चाहिए जिनमें वह गाना मौजूद है.

दोनों ही मामलों में, एंटिटी के बीच रिलेशनशिप को मॉडल करें. इसके लिए, इन दोनों क्लास में @Relation एनोटेशन में associateBy प्रॉपर्टी का इस्तेमाल करें. इससे, 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>
)

आखिर में, डेटा ऐक्सेस ऑब्जेक्ट (डीएओ) क्लास में एक फ़ंक्शन जोड़ें, ताकि आपके ऐप्लिकेशन के लिए ज़रूरी क्वेरी फ़ंक्शन को दिखाया जा सके.

getPlaylistsWithSongs
डेटाबेस पर क्वेरी करता है और क्वेरी के नतीजे के तौर पर मिले सभी PlaylistWithSongs ऑब्जेक्ट दिखाता है.
getSongsWithPlaylists
डेटाबेस पर क्वेरी करता है और क्वेरी के नतीजे के तौर पर मिले सभी SongWithPlaylists ऑब्जेक्ट दिखाता है.

हर फ़ंक्शन के लिए, Room को दो क्वेरी चलाने की ज़रूरत होती है. दोनों फ़ंक्शन में @Transaction एनोटेशन जोड़ें, ताकि यह पक्का किया जा सके कि ऑपरेशन एटॉमिक तरीके से चले.

@Transaction
@Query("SELECT * FROM Playlist")
suspend fun getPlaylistsWithSongs(): List<PlaylistWithSongs>

@Transaction
@Query("SELECT * FROM Song")
suspend fun getSongsWithPlaylists(): List<SongWithPlaylists>

कंपोज़िट की

अगर कंपोज़िट की का इस्तेमाल करके रिलेशनशिप तय किया जाता है, तो @Relation एनोटेशन के parentColumns और entityColumns में एक से ज़्यादा कॉलम तय करें.

अगर आपको Junction में कॉलम तय करने हैं, तो Junction एनोटेशन में parentColumns और entityColumns का भी इस्तेमाल करें.

यहां दिए गए उदाहरण में, 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>
)