যেহেতু SQLite একটি রিলেশনাল ডেটাবেস, তাই আপনি এনটিটিগুলোর মধ্যে সম্পর্ক স্থাপন করতে পারেন। কিন্তু বেশিরভাগ অবজেক্ট-রিলেশনাল ম্যাপিং লাইব্রেরি যেখানে এনটিটি অবজেক্টগুলোকে একে অপরকে রেফারেন্স করতে দেয়, সেখানে Room স্পষ্টভাবে এটি নিষিদ্ধ করে। এই সিদ্ধান্তের পেছনের প্রযুক্তিগত কারণ সম্পর্কে জানতে, "Understand why Room doesn't allow object references " দেখুন।
সম্পর্কের প্রকারভেদ
রুম নিম্নলিখিত সম্পর্ক প্রকারগুলি সমর্থন করে:
- এক-এক : এমন একটি সম্পর্ককে বোঝায় যেখানে একটি সত্তা অন্য একটি সত্তার সাথে সম্পর্কিত থাকে।
- এক-থেকে-অনেক : এমন একটি সম্পর্ককে বোঝায় যেখানে একটি একক সত্তা অন্য ধরনের একাধিক সত্তার সাথে সম্পর্কিত হতে পারে।
- মেনি-টু-মেনি : এমন একটি সম্পর্ককে বোঝায় যেখানে এক ধরনের একাধিক এনটিটি অন্য ধরনের একাধিক এনটিটির সাথে সম্পর্কিত হতে পারে। এর জন্য সাধারণত একটি জাংশন টেবিলের প্রয়োজন হয়।
- এমবেডেড অবজেক্ট ব্যবহার করে নেস্টেড সম্পর্ক : এটি এমন একটি সম্পর্ককে বোঝায় যেখানে একটি এনটিটি অন্য একটি এনটিটিকে প্রপার্টি হিসেবে ধারণ করে, এবং এই নেস্টেড এনটিটিটিটি আরও অন্যান্য এনটিটিকে ধারণ করতে পারে। এর জন্য
@Embeddedঅ্যানোটেশনটি ব্যবহৃত হয়।
দুটি পদ্ধতির মধ্যে একটি বেছে নিন
Room-এ, এনটিটিগুলোর মধ্যে সম্পর্ক সংজ্ঞায়িত এবং কোয়েরি করার দুটি উপায় রয়েছে:
- এমবেডেড অবজেক্ট সহ একটি মধ্যবর্তী ডেটা ক্লাস, অথবা
- মাল্টিম্যাপ রিটার্ন টাইপ সহ একটি রিলেশনাল কোয়েরি ফাংশন।
মধ্যবর্তী ডেটা ক্লাস ব্যবহার করার কোনো নির্দিষ্ট কারণ না থাকলে, আমরা মাল্টিম্যাপ রিটার্ন টাইপ পদ্ধতিটি ব্যবহার করার পরামর্শ দিই। এই পদ্ধতি সম্পর্কে আরও জানতে, “Return a multimap” দেখুন।
ইন্টারমিডিয়েট ডেটা ক্লাস পদ্ধতি আপনাকে জটিল SQL কোয়েরি লেখা এড়াতে সাহায্য করে, কিন্তু এর ফলে কোডের জটিলতাও বেড়ে যেতে পারে, কারণ এর জন্য অতিরিক্ত ডেটা ক্লাসের প্রয়োজন হয়। সংক্ষেপে, মাল্টিম্যাপ রিটার্ন টাইপ পদ্ধতিতে আপনার SQL কোয়েরিগুলোকে বেশি কাজ করতে হয়, এবং ইন্টারমিডিয়েট ডেটা ক্লাস পদ্ধতিতে আপনার কোডকেও বেশি কাজ করতে হয়।
মধ্যবর্তী ডেটা ক্লাস পদ্ধতি ব্যবহার করুন
ইন্টারমিডিয়েট ডেটা ক্লাস পদ্ধতিতে, আপনি এমন একটি ডেটা ক্লাস সংজ্ঞায়িত করেন যা আপনার Room এনটিটিগুলোর মধ্যকার সম্পর্ককে মডেল করে। এই ডেটা ক্লাসটি একটি এনটিটির ইনস্ট্যান্সের সাথে অন্য একটি এনটিটির ইনস্ট্যান্সের জোড়গুলোকে এমবেডেড অবজেক্ট হিসেবে ধারণ করে। এরপর আপনার কোয়েরি ফাংশনগুলো আপনার অ্যাপে ব্যবহারের জন্য এই ডেটা ক্লাসের ইনস্ট্যান্সগুলো রিটার্ন করতে পারে।
উদাহরণস্বরূপ, আপনি নির্দিষ্ট বই ধার নেওয়া লাইব্রেরি ব্যবহারকারীদের প্রতিনিধিত্ব করার জন্য একটি UserBook ডেটা ক্লাস সংজ্ঞায়িত করতে পারেন, এবং ডাটাবেস থেকে UserBook ইনস্ট্যান্সগুলির একটি তালিকা পুনরুদ্ধার করার জন্য একটি কোয়েরি ফাংশন সংজ্ঞায়িত করতে পারেন:
@Dao interface UserBookDao { @Query( """ SELECT user.name AS userName, book.name AS bookName FROM user JOIN book ON user.id = book.user_id """ ) fun loadUserAndBookNames(): LiveData<List<UserBook>> } data class UserBook(val userName: String, val bookName: String)
মাল্টিম্যাপ রিটার্ন টাইপ পদ্ধতি ব্যবহার করুন
মাল্টিম্যাপ রিটার্ন টাইপ পদ্ধতিতে, আপনাকে কোনো অতিরিক্ত ডেটা ক্লাস সংজ্ঞায়িত করতে হয় না। এর পরিবর্তে, আপনি আপনার কাঙ্ক্ষিত ম্যাপ কাঠামোর উপর ভিত্তি করে আপনার ফাংশনের জন্য একটি মাল্টিম্যাপ রিটার্ন টাইপ সংজ্ঞায়িত করেন এবং আপনার SQL কোয়েরিতে সরাসরি এনটিটিগুলোর মধ্যে সম্পর্ক নির্ধারণ করেন।
উদাহরণস্বরূপ, নিম্নলিখিত কোয়েরি ফাংশনটি User এবং Book ইনস্ট্যান্সগুলির একটি ম্যাপিং রিটার্ন করে, যা নির্দিষ্ট বই চেক আউট করা লাইব্রেরি ব্যবহারকারীদের প্রতিনিধিত্ব করে:
@Query( """ SELECT * FROM user JOIN book ON user.id = book.user_id """ ) suspend fun loadUserAndBookNames(): Map<User, List<Book>>
মাল্টিম্যাপ রিটার্ন টাইপের সাহায্যে, আপনি এমন ওয়ান-টু-ওয়ান সম্পর্কও কোয়েরি করতে পারেন যেখানে অন্য কোনো এনটিটি জড়িত থাকে না। নিম্নলিখিত কোয়েরি ফাংশনটি @MapColumn অ্যানোটেশন ব্যবহার করে একজন User এবং তার চেক আউট করা বইয়ের সংখ্যার একটি ম্যাপিং রিটার্ন করে:
@Query( """ SELECT user.*, COUNT(book.id) AS book_count FROM user LEFT JOIN book ON user.id = book.user_id GROUP BY user.id """ ) suspend fun loadUserAndBookCount(): Map<User, @MapColumn(columnName = "book_count") Int>
এমবেডেড অবজেক্ট তৈরি করুন
কখনও কখনও, আপনি আপনার ডাটাবেস লজিকে একটি সত্তা বা ডেটা অবজেক্টকে একটি সুসংহত সত্তা হিসেবে প্রকাশ করতে চান, এমনকি যদি অবজেক্টটিতে একাধিক প্রোপার্টি থাকে। এই পরিস্থিতিতে, একটি টেবিলের মধ্যে কোনো অবজেক্টকে তার উপ-প্রোপার্টিগুলোতে বিভক্ত করতে @Embedded অ্যানোটেশনটি ব্যবহার করুন। এরপর আপনি অন্যান্য কলামের মতোই এমবেডেড প্রোপার্টিগুলো কোয়েরি করতে পারবেন।
উদাহরণস্বরূপ, আপনার User ক্লাসে একটি Address প্রপার্টি থাকতে পারে যা street , city , state , এবং postCode প্রপার্টিগুলোর একটি সংমিশ্রণকে উপস্থাপন করে। টেবিলে এই সংমিশ্রিত কলামগুলোকে আলাদাভাবে সংরক্ষণ করতে, User ক্লাসের Address প্রপার্টিটিকে @Embedded দিয়ে অ্যানোটেট করুন। নিচের কোড স্নিপেটটি এই সেটআপটি প্রদর্শন করে:
data class Address( val street: String?, val state: String?, val city: String?, @ColumnInfo(name = "post_code") val postCode: Int ) @Entity data class User( @PrimaryKey val id: Int, val firstName: String, @Embedded val address: Address? )
একটি User অবজেক্টের প্রতিনিধিত্বকারী টেবিলটিতে id , firstName , street , state , city এবং post_code নামের কলামগুলো থাকে।
যদি কোনো এনটিটির একই ধরনের একাধিক এমবেডেড প্রপার্টি থাকে, তাহলে আপনি prefix প্রপার্টি সেট করে প্রতিটি কলামকে স্বতন্ত্র রাখতে পারেন। এরপর Room এমবেডেড অবজেক্টের প্রতিটি কলাম নামের শুরুতে প্রদত্ত মানটি যোগ করে দেয়।