SQLite एक रिलेशनल डेटाबेस है. इसलिए, इसमें इकाइयों के बीच संबंध तय किए जा सकते हैं. हालांकि, ज़्यादातर ऑब्जेक्ट-रिलेशनल मैपिंग लाइब्रेरी, इकाई ऑब्जेक्ट को एक-दूसरे को रेफ़रंस करने की अनुमति देती हैं. वहीं, Room इस पर साफ़ तौर पर पाबंदी लगाता है. इस फ़ैसले के पीछे की तकनीकी वजह जानने के लिए, जानें कि Room, ऑब्जेक्ट रेफ़रंस की अनुमति क्यों नहीं देता लेख पढ़ें.
अलग-अलग तरह के संबंध
Room में, इन तरह के संबंधों को मैनेज किया जा सकता है:
- वन-टू-वन: यह एक ऐसा रिलेशनशिप होता है जिसमें एक इकाई, दूसरी इकाई से जुड़ी होती है.
- वन-टू-मेनी: यह एक ऐसा रिलेशनशिप होता है जिसमें एक इकाई, दूसरी तरह की कई इकाइयों से जुड़ी हो सकती है.
- कई से कई: यह एक ऐसा रिलेशनशिप होता है जिसमें एक टाइप की कई इकाइयां, दूसरे टाइप की कई इकाइयों से जुड़ी हो सकती हैं. इसके लिए, आम तौर पर जंक्शन टेबल की ज़रूरत होती है.
- नेस्ट किए गए रिलेशनशिप (एम्बेड किए गए ऑब्जेक्ट का इस्तेमाल करके): यह एक ऐसे रिलेशनशिप को दिखाता है जिसमें एक इकाई में दूसरी इकाई को फ़ील्ड के तौर पर शामिल किया जाता है. साथ ही, इस नेस्ट की गई इकाई में अन्य इकाइयों को भी शामिल किया जा सकता है. यह
@Embeddedएनोटेशन का इस्तेमाल करता है.
दो में से कोई एक तरीका चुनना
Room में, इकाइयों के बीच संबंध को तय करने और उससे जुड़ी क्वेरी करने के दो तरीके हैं. इनमें से किसी एक का इस्तेमाल किया जा सकता है:
- एम्बेड किए गए ऑब्जेक्ट वाली इंटरमीडिएट डेटा क्लास या
- यह एक रिलेशनल क्वेरी का तरीका है. इसमें मल्टीमैप के तौर पर डेटा मिलता है.
अगर आपके पास इंटरमीडिएट डेटा क्लास इस्तेमाल करने की कोई खास वजह नहीं है, तो हमारा सुझाव है कि मल्टीमैप रिटर्न टाइप का इस्तेमाल करें. इस तरीके के बारे में ज़्यादा जानने के लिए, मल्टीमैप वापस पाना लेख पढ़ें.
इंटरमीडिएट डेटा क्लास के तरीके से, जटिल एसक्यूएल क्वेरी लिखने से बचा जा सकता है. हालांकि, इससे कोड की जटिलता भी बढ़ सकती है, क्योंकि इसके लिए अतिरिक्त डेटा क्लास की ज़रूरत होती है. संक्षेप में, मल्टीमैप रिटर्न टाइप के तरीके में, आपकी SQL क्वेरी को ज़्यादा काम करना पड़ता है. वहीं, इंटरमीडिएट डेटा क्लास के तरीके में, आपके कोड को ज़्यादा काम करना पड़ता है.
इंटरमीडिएट डेटा क्लास का इस्तेमाल करना
इंटरमीडिएट डेटा क्लास के तरीके में, एक ऐसी डेटा क्लास तय की जाती है जो आपकी रूम इकाइयों के बीच के संबंध को मॉडल करती है. इस डेटा क्लास में, एक इकाई के इंस्टेंस और दूसरी इकाई के इंस्टेंस के बीच की जोड़ियां, एम्बेड किए गए ऑब्जेक्ट के तौर पर सेव होती हैं. इसके बाद, क्वेरी के तरीके, इस डेटा क्लास के इंस्टेंस को आपके ऐप्लिकेशन में इस्तेमाल करने के लिए वापस भेज सकते हैं.
उदाहरण के लिए, लाइब्रेरी के उपयोगकर्ताओं को दिखाने के लिए, UserBook डेटा क्लास को तय किया जा सकता है. इसमें उन उपयोगकर्ताओं की जानकारी होती है जिन्होंने कुछ खास किताबें ली हैं. साथ ही, डेटाबेस से UserBook इंस्टेंस की सूची पाने के लिए, क्वेरी के तरीके को तय किया जा सकता है:
Kotlin
@Dao
interface UserBookDao {
@Query(
"SELECT user.name AS userName, book.name AS bookName " +
"FROM user, book " +
"WHERE user.id = book.user_id"
)
fun loadUserAndBookNames(): LiveData<List<UserBook>>
}
data class UserBook(val userName: String?, val bookName: String?)
Java
@Dao
public interface UserBookDao {
@Query("SELECT user.name AS userName, book.name AS bookName " +
"FROM user, book " +
"WHERE user.id = book.user_id")
public LiveData<List<UserBook>> loadUserAndBookNames();
}
public class UserBook {
public String userName;
public String bookName;
}
मल्टीमैप रिटर्न टाइप का इस्तेमाल करना
मल्टीमैप रिटर्न टाइप के तरीके में, आपको कोई अतिरिक्त डेटा क्लास तय करने की ज़रूरत नहीं होती. इसके बजाय, आपको जिस मैप स्ट्रक्चर की ज़रूरत है उसके आधार पर, अपने तरीके के लिए multimap रिटर्न टाइप तय करें. साथ ही, अपनी एसक्यूएल क्वेरी में सीधे तौर पर अपनी इकाइयों के बीच संबंध तय करें.
उदाहरण के लिए, यहां दिया गया क्वेरी मेथड, User और Book इंस्टेंस की मैपिंग दिखाता है. इससे, लाइब्रेरी के उन उपयोगकर्ताओं के बारे में पता चलता है जिन्होंने कुछ खास किताबें ली हैं:
Kotlin
@Query(
"SELECT * FROM user" +
"JOIN book ON user.id = book.user_id"
)
fun loadUserAndBookNames(): Map<User, List<Book>>
Java
@Query(
"SELECT * FROM user" +
"JOIN book ON user.id = book.user_id"
)
public Map<User, List<Book>> loadUserAndBookNames();
एम्बेड किए गए ऑब्जेक्ट बनाना
कभी-कभी, आपको अपने डेटाबेस लॉजिक में किसी इकाई या डेटा ऑब्जेक्ट को एक साथ दिखाना होता है. भले ही, ऑब्जेक्ट में कई फ़ील्ड शामिल हों. इन स्थितियों में, @Embedded एनोटेशन का इस्तेमाल करके, किसी ऑब्जेक्ट को दिखाया जा सकता है. इस ऑब्जेक्ट को टेबल में मौजूद इसके सब-फ़ील्ड में बांटा जा सकता है. इसके बाद, एम्बेड किए गए फ़ील्ड के लिए क्वेरी की जा सकती है. ठीक उसी तरह जैसे अन्य कॉलम के लिए क्वेरी की जाती है.
उदाहरण के लिए, आपकी User क्लास में Address टाइप का फ़ील्ड शामिल हो सकता है. यह street, city, state, और postCode नाम वाले फ़ील्ड के कंपोज़िशन को दिखाता है. कंपोज़ किए गए कॉलम को टेबल में अलग-अलग स्टोर करने के लिए, Address फ़ील्ड शामिल करें. यह User क्लास में @Embedded के साथ एनोटेट किया गया होना चाहिए. यहां दिए गए कोड स्निपेट से पता चलता है कि यह कैसे काम करता है:
Kotlin
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?
)
Java
public class Address {
public String street;
public String state;
public String city;
@ColumnInfo(name = "post_code") public int postCode;
}
@Entity
public class User {
@PrimaryKey public int id;
public String firstName;
@Embedded public Address address;
}
User ऑब्जेक्ट को दिखाने वाली टेबल में, इन नामों वाले कॉलम होते हैं: id, firstName, street, state, city, और post_code.
अगर किसी इकाई में एक ही तरह के कई एम्बेड किए गए फ़ील्ड हैं, तो prefix प्रॉपर्टी सेट करके, हर कॉलम को यूनीक रखा जा सकता है. इसके बाद, Room, एम्बेड किए गए ऑब्जेक्ट में मौजूद हर कॉलम के नाम की शुरुआत में दी गई वैल्यू जोड़ता है.
अन्य संसाधन
Room में मौजूद इकाइयों के बीच संबंध तय करने के बारे में ज़्यादा जानने के लिए, यहां दिए गए अतिरिक्त संसाधन देखें.
वीडियो
- Room में नया क्या है (Android Dev Summit '19)