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

দুটি এন্টিটির মধ্যে মাল্টিপল-টু-মাল্টিপল সম্পর্ক হল এমন একটি সম্পর্ক যেখানে পেরেন্ট এন্টিটির প্রতিটি ইনস্ট্যান্স চাইল্ড এন্টিটির শূন্য বা একাধিক ইনস্ট্যান্সের সাথে সম্পর্কিত এবং এর বিপরীতটিও সত্য।

মিউজিক স্ট্রিমিং অ্যাপের উদাহরণে, ব্যবহারকারীর সংজ্ঞায়িত প্লেলিস্টে থাকা গানগুলি বিবেচনা করুন। প্রতিটি প্লেলিস্টে অনেক গান থাকতে পারে এবং প্রতিটি গান অনেক প্লেলিস্টে থাকতে পারে। তাই, 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 অবজেক্টের তালিকা থাকে।

দুটি ক্ষেত্রেই, Playlist এন্টিটি ও Song এন্টিটির মধ্যে সম্পর্ক প্রদানকারী ক্রস-রেফারেন্স এন্টিটি শনাক্ত করতে, এই ক্লাসগুলির প্রত্যেকটিতে @Relation অ্যানোটেশনে associateBy প্রপার্টি ব্যবহার করে এন্টিটিগুলির মধ্যে সম্পর্ক মডেল করুন।

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-এর প্রয়োজন হয়। অপারেশন যাতে অ্যাটমিকভাবে রান করে তা নিশ্চিত করতে, দুটি ফাংশনেই @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>
)