بما أنّ SQLite هي قاعدة بيانات ارتباطية، يمكنك تحديد العلاقات بين الكيانات. ومع ذلك، في حين أنّ معظم مكتبات ربط البيانات العلائقية بالكائنات تتيح للكائنات الممثلة للكيانات الإشارة إلى بعضها البعض، فإنّ Room تحظر ذلك بشكل صريح. لمعرفة الأسباب الفنية وراء هذا القرار، يُرجى الاطّلاع على فهم سبب عدم سماح Room بمراجع الكائنات.
أنواع العلاقات
يتيح Room أنواع العلاقات التالية:
- علاقة رأس برأس: تمثّل علاقة يكون فيها كيان واحد مرتبطًا بكيان واحد آخر.
- علاقة رأس بأطراف: تمثّل علاقة يمكن فيها ربط كيان واحد بعدة كيانات من نوع آخر.
- علاقة أطراف بأطراف: تمثّل علاقة يمكن فيها ربط عدة كيانات من نوع واحد بعدة كيانات من نوع آخر. يتطلّب ذلك عادةً جدول ربط.
- العلاقات المتداخلة باستخدام الكائنات المضمّنة: تمثّل علاقة يتضمّن فيها أحد العناصر عنصرًا آخر كسمة، ويمكن أن يتضمّن هذا العنصر المتداخل عناصر أخرى. يستخدم هذا الإجراء التعليق التوضيحي
@Embedded.
اختيار إحدى الطريقتَين
في Room، هناك طريقتان لتحديد علاقة بين عناصر والبحث عنها. يمكنك استخدام أي مما يلي:
- فئة بيانات وسيطة تحتوي على عناصر مضمّنة
- دالة طلب بحث علائقي مع نوع القيمة التي تم إرجاعها خريطة متعدّدة.
إذا لم يكن لديك سبب محدّد لاستخدام فئات البيانات الوسيطة، ننصحك باستخدام أسلوب نوع القيمة التي تم إرجاعها multimap. لمزيد من المعلومات حول هذا الأسلوب، يُرجى الاطّلاع على عرض خريطة متعددة.
يتيح لك أسلوب فئة البيانات الوسيطة تجنُّب كتابة طلبات بحث SQL معقّدة، ولكنّه قد يؤدي أيضًا إلى زيادة تعقيد الرموز البرمجية لأنّه يتطلّب فئات بيانات إضافية. باختصار، يتطلّب أسلوب نوع القيمة التي تم إرجاعها multimap أن تنفّذ استعلامات 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)
استخدام أسلوب نوع القيمة التي تم إرجاعها multimap
في طريقة نوع القيمة التي تم إرجاعها المتعدد الخرائط، لست بحاجة إلى تحديد أي فئات بيانات إضافية. بدلاً من ذلك، يمكنك تحديد نوع القيمة التي تم إرجاعها multimap للدالة استنادًا إلى بنية الخريطة التي تريدها، وتحديد العلاقة بين الكيانات مباشرةً في طلب بحث لغة الاستعلامات البنيوية (SQL).
على سبيل المثال، تعرض دالة طلب البحث التالية عملية ربط بين مثيلات User وBook
لتمثيل مستخدمي المكتبة الذين استعاروا كتبًا معيّنة:
@Query( """ SELECT * FROM user JOIN book ON user.id = book.user_id """ ) suspend fun loadUserAndBookNames(): Map<User, List<Book>>
باستخدام أنواع الإرجاع المتعددة الخرائط، يمكنك أيضًا طلب البحث عن علاقات رأس برأس لا تتضمّن كيانًا آخر. تعرض دالة طلب البحث التالية عملية ربط بين
User وعدد الكتب التي تمت استعارتها باستخدام التعليق التوضيحي
@MapColumn:
@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. لتخزين الأعمدة المركّبة بشكل منفصل في الجدول، أضِف تعليقًا توضيحيًا إلى السمة Address في الفئة User باستخدام @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 بعد ذلك القيمة المقدَّمة إلى بداية كل اسم عمود في العنصر المضمّن.