নেস্টেড সম্পর্ককে সংজ্ঞায়িত ও কোয়েরি করা

কখনও কখনও, আপনাকে তিন বা তার বেশি টেবিলের একটি সেট কোয়েরি করতে হতে পারে যেগুলি একে অপরের সাথে সম্পর্কিত। সেই ক্ষেত্রে, আপনি টেবিলের মধ্যে নেস্টেড সম্পর্ক নির্ধারণ করেন।

ধরা যাক, মিউজিক স্ট্রিমিং অ্যাপের উদাহরণে, আপনি সব ব্যবহারকারী, প্রতিটি ব্যবহারকারীর জন্য সব প্লেলিস্ট এবং প্রতিটি ব্যবহারকারীর জন্য প্রতিটি প্লেলিস্টের সব গান কোয়েরি করতে চান। ব্যবহারকারীদের সাথে প্লেলিস্টের এক-থেকে-একাধিক সম্পর্ক থাকে এবং প্লেলিস্টের সাথে গানের একাধিক-থেকে-একাধিক সম্পর্ক থাকে। নিম্নলিখিত কোড উদাহরণে এমন ক্লাস দেখানো হয়েছে যা এই এন্টিটিগুলিকে উপস্থাপন করে, সেইসাথে প্লেলিস্ট ও গানের মধ্যে থাকা 'অনেক-থেকে-অনেকে' সম্পর্ককে ক্রস-রেফারেন্স টেবিলের মাধ্যমে দেখানো হয়েছে:

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

প্রথমে, আপনার সেটের দুটি টেবিলের মধ্যে সম্পর্ক মডেল করুন, যেভাবে আপনি সাধারণত করেন, ডেটা ক্লাস এবং @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 ক্লাসটি User, Playlist ও Song, এই তিনটি এন্টিটি ক্লাসের মধ্যে সম্পর্ককে পরোক্ষভাবে মডেল করে। এটি ছবি ১-এ দেখানো হয়েছে।

UserWithPlaylistsAndSongs মডেলটি User এবং
  PlaylistWithSongs-এর মধ্যে সম্পর্ককে মডেল করে, যা আবার Playlist
  এবং Song-এর মধ্যে সম্পর্ককে মডেল করে।
ছবি ১. মিউজিক স্ট্রিমিং অ্যাপের উদাহরণে সম্পর্কযুক্ত ক্লাসের ডায়াগ্রাম।

আপনার সেটে আরও টেবিল থাকলে, প্রতিটি অবশিষ্ট টেবিল এবং আগের রিলেশনশিপ ক্লাসের মধ্যে সম্পর্ক মডেল করার জন্য একটি ক্লাস তৈরি করুন। এই প্রসেসটি কোয়েরি করতে চান এমন সব টেবিলের মধ্যে নেস্টেড সম্পর্কের একটি চেইন তৈরি করে।

সবশেষে, আপনার অ্যাপের প্রয়োজনীয় কোয়েরি ফাংশনটি প্রকাশ করতে, ডেটা অ্যাক্সেস অবজেক্ট (DAO) ক্লাসে একটি ফাংশন যোগ করুন। এই ফাংশনের জন্য Room-কে একাধিক কোয়েরি রান করাতে হয়, তাই @Transaction অ্যানোটেশন যোগ করুন যাতে সম্পূর্ণ অপারেশন অ্যাটমিক হিসেবে রান করে:

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