بما أنّ SQLite هي قاعدة بيانات ارتباطية، يمكنك تحديد العلاقات بين الكيانات. ولكن في حين أنّ معظم مكتبات الربط بين الكائنات والعلاقات تسمح لكائنات العناصر بإحالة بعضها إلى بعض، يحظر Room ذلك صراحةً. للتعرّف على ال reasoning العميق المتعلّق بهذا القرار، اطّلِع على مقالة فهم سبب عدم السماح بمراجع العناصر في Room.
أنواع العلاقات
تتيح الغرفة أنواع العلاقات التالية:
- رأس برأس: يمثّل علاقة يكون فيها كيان واحد مرتبطًا بكيان آخر.
- واحد إلى عدّة: يمثّل علاقة يمكن فيها أن يكون كيان واحد مرتبطًا بكيانات متعدّدة من نوع آخر.
- أطراف بأطراف: يمثّل علاقة يمكن فيها ربط كيانات متعددة من نوع واحد بكيانات متعددة من نوع آخر. يتطلّب ذلك عادةً جدول ربط.
- العلاقات المُدمجة (باستخدام العناصر المضمّنة): تمثّل
علاقة يتضمّن فيها كيان كيانًا آخر كحقل، ويمكن أن يتضمّن هذا
الكيان المُدمَج كيانات أخرى. ويستخدم هذا الإجراء التعليق التوضيحي
@Embedded
.
اختيار بين طريقتَين
في Room، هناك طريقتان لتحديد علاقة بين الكيانات وإجراء طلب بحث عنها. يمكنك استخدام أيّ من الخيارَين التاليَين:
- فئة بيانات وسيطة تحتوي على عناصر مضمّنة
- طريقة طلب ارتباطية بنوع إرجاع خريطة متعددة
إذا لم يكن لديك سبب محدّد لاستخدام فئات البيانات الوسيطة، ننصحك باستخدام نهج نوع الإرجاع في الخريطة المتعددة. للاطّلاع على مزيد من المعلومات عن هذا الأسلوب، اطّلِع على عرض خريطة متعددة.
يتيح لك منهج فئة البيانات الوسيطة تجنُّب كتابة طلبات بحث SQL معقّدة، ولكن يمكن أن يؤدي ذلك أيضًا إلى زيادة تعقيد الرمز البرمجي لأنّه يتطلّب فئات بيانات إضافية. باختصار، يتطلب أسلوب نوع الإرجاع في الخارطة المتعددة أن تُجري استعلامات SQL المزيد من العمل، ويتطلب أسلوب فئة البيانات الوسيطة أن تُجري رمزك البرمجي المزيد من العمل.
استخدام نهج فئة البيانات الوسيطة
في نهج فئة البيانات الوسيطة، يمكنك تحديد فئة بيانات تنشئ نموذجًا لعلاقته بين الكيانات Room. تحتوي فئة البيانات هذه على عمليات الإقران بين نُسخ عنصر واحد ونُسخ عنصر آخر على شكل عناصر مضمّنة. يمكن بعد ذلك لطرق طلبات البحث عرض نُسخ من فئة البيانات هذه بهدف استخدامها في تطبيقك.
على سبيل المثال، يمكنك تحديد فئة بيانات 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;
}
استخدام نهج أنواع الإرجاع في الخارطة المتعددة
في نهج نوع الإرجاع "الخريطة المتعددة"، لا تحتاج إلى تحديد أي مزيد من فئات البيانات. بدلاً من ذلك، يمكنك تحديد نوع إرجاع قائمة متعددة لسمة الطريقة استنادًا إلى بنية الخريطة التي تريدها وتحديد العلاقة بين كياناتك مباشرةً في طلب بحث SQL.
على سبيل المثال، تُرجِع طريقة طلب البحث التالية تعيينًا لمثيلَي 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 (مؤتمر Android Dev Summit لعام 2019)