توفّر الغرفة وظيفة للتحويل بين الأنواع الأساسية والنمطية، ولكنها لا تسمح بمراجع العناصر بين الكيانات. يشرح هذا المستند كيفية استخدام محولات الأنواع ولماذا لا تدعم الغرفة مراجع العناصر.
استخدام أدوات تحويل الأنواع
في بعض الأحيان، تحتاج إلى تطبيقك لتخزين نوع بيانات مخصص في عمود قاعدة بيانات
واحد. يمكنك إتاحة الأنواع المخصّصة من خلال توفير برامج تحويل الأنواع، وهي طرق توضّح لغرفة كيفية تحويل الأنواع المخصّصة من الأنواع المعروفة التي يمكن أن تستمرّ إليها
الغرفة ومنها. يمكنك تحديد منفِّذي الإحالات الناجحة باستخدام التعليق التوضيحي
@TypeConverter
.
فرضًا أنّك تحتاج إلى الاحتفاظ بمثيلات من Date
في
قاعدة بيانات الغرفة. لا يعرف Room كيفية الاحتفاظ بكائنات Date
، لذلك تحتاج إلى تحديد أنواع المحوِّلات:
Kotlin
class Converters { @TypeConverter fun fromTimestamp(value: Long?): Date? { return value?.let { Date(it) } } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time?.toLong() } }
Java
public class Converters { @TypeConverter public static Date fromTimestamp(Long value) { return value == null ? null : new Date(value); } @TypeConverter public static Long dateToTimestamp(Date date) { return date == null ? null : date.getTime(); } }
يحدّد هذا المثال طريقتَي تحويل من النوع: الطريقة التي تحوِّل كائن Date
إلى كائن Long
والأخرى تنفّذ التحويل العكسي من Long
إلى Date
. ولأنّ الغرفة تعرف كيفية الاحتفاظ بكائنات Long
، يمكنها استخدام
برامج الإحالات الناجحة هذه للاحتفاظ بعناصر Date
.
بعد ذلك، يمكنك إضافة التعليق التوضيحي @TypeConverters
إلى فئة AppDatabase
حتى تتعرّف الغرفة على فئة المحوِّل
التي حددتها:
Kotlin
@Database(entities = [User::class], version = 1) @TypeConverters(Converters::class) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
Java
@Database(entities = {User.class}, version = 1) @TypeConverters({Converters.class}) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
مع تحديد هذه الأنواع من المحولات، يمكنك استخدام النوع المخصص في الكيانات وقوائم DAO تمامًا كما تستخدم الأنواع الأساسية:
Kotlin
@Entity data class User(private val birthday: Date?) @Dao interface UserDao { @Query("SELECT * FROM user WHERE birthday = :targetDate") fun findUsersBornOnDate(targetDate: Date): List<User> }
Java
@Entity public class User { private Date birthday; } @Dao public interface UserDao { @Query("SELECT * FROM user WHERE birthday = :targetDate") List<User> findUsersBornOnDate(Date targetDate); }
في هذا المثال، يمكن أن تستخدم Room محوِّل النوع المحدّد في كل مكان لأنك أضفت تعليقًا توضيحيًا إلى AppDatabase
باستخدام @TypeConverters
. مع ذلك، يمكنك أيضًا تحديد نطاق المحولين في أنواع
المحولات إلى كيانات محدّدة أو قوائم DAO من خلال إضافة تعليقات توضيحية إلى فئتَي @Entity
أو @Dao
باستخدام @TypeConverters
.
ضبط إعدادات محوّل نوع التحكّم
عادةً ما تعالج الغرفة مثيلاً لمحولات الأنواع نيابةً عنك. ومع ذلك، قد تحتاج في بعض الأحيان إلى تمرير تبعيات إضافية إلى فئات محولات الأنواع لديك، ما يعني أنك في حاجة إلى تطبيقك للتحكُّم مباشرةً في إعداد محوّلات الأنواع لديك. في هذه الحالة، أضِف تعليقًا توضيحيًا على فئة المحوّل باستخدام
@ProvidedTypeConverter
:
Kotlin
@ProvidedTypeConverter class ExampleConverter { @TypeConverter fun StringToExample(string: String?): ExampleType? { ... } @TypeConverter fun ExampleToString(example: ExampleType?): String? { ... } }
Java
@ProvidedTypeConverter public class ExampleConverter { @TypeConverter public Example StringToExample(String string) { ... } @TypeConverter public String ExampleToString(Example example) { ... } }
بعد ذلك، بالإضافة إلى تعريف فئة المحوّل في @TypeConverters
، استخدِم الطريقة
RoomDatabase.Builder.addTypeConverter()
لتمرير مثيل من فئة المحوّل إلى
أداة إنشاء RoomDatabase
:
Kotlin
val db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build()
Java
AppDatabase db = Room.databaseBuilder(...) .addTypeConverter(exampleConverterInstance) .build();
فهم سبب عدم سماح الغرفة بإشارات العناصر
نصيحة رئيسية: لا تسمح الغرفة بإشارات العناصر بين فئات الكيانات. بدلاً من ذلك، يجب عليك طلب البيانات التي يحتاجها تطبيقك صراحةً.
إن تعيين العلاقات من قاعدة بيانات بنموذج الكائن ذي الصلة هو ممارسة شائعة ويعمل بشكل جيد للغاية على الخادم. حتى عندما يقوم البرنامج بتحميل الحقول عند الوصول إليها، يظل الخادم يعمل بشكل جيد.
أمّا من جهة العميل، فليس بالإمكان تحميل هذا النوع من "التحميل الكسول" لأنّه يحدث عادةً في سلسلة تعليمات واجهة المستخدم، ويؤدي طلب البحث عن معلومات على القرص في سلسلة واجهة المستخدم إلى حدوث مشاكل كبيرة في الأداء. إنّ مؤشر ترابط واجهة المستخدم عادةً ما يستغرق حوالي 16 ملي ثانية لحساب التنسيق المحدَّث للنشاط ورسمه، لذا حتى إذا استغرق طلب البحث 5 ملي ثانية فقط، من المحتمل أن ينفد الوقت الذي يستغرقه تطبيقك لرسم الإطار، ما يتسبّب في حدوث أعطال مرئية ملحوظة. قد يستغرق الاستعلام مزيدًا من الوقت حتى يتم إكماله إذا كانت هناك معاملة منفصلة تعمل بالتوازي، أو إذا كان الجهاز يقوم بتشغيل مهام أخرى كثيفة الاستخدام للقرص. إذا كنت لا تستخدم التحميل الكسول، فإن تطبيقك يجلب بيانات أكثر مما يحتاج إليه، مما يتسبب في حدوث مشاكل في استهلاك الذاكرة.
عادةً ما تترك التعيينات الارتباطية الكائنة هذا القرار للمطورين حتى يتمكنوا من فعل كل ما هو أفضل لحالات استخدام تطبيقاتهم. يقرر المطورون عادةً مشاركة النموذج بين تطبيقهم وواجهة المستخدم. ومع ذلك، لا يتسع نطاق هذا الحل بشكل جيد، لأنّه مع تغيّر واجهة المستخدم بمرور الوقت، يخلق النموذج المشترَك مشاكل يصعب على المطوّرين توقّعها وتصحيح أخطائها.
على سبيل المثال، جرِّب واجهة مستخدم تحمِّل قائمة بعناصر Book
، على أن يحتوي كل كتاب على عنصر Author
. قد تصمّم طلبات البحث في البداية لاستخدام التحميل الكسول
للحصول على مثيلات Book
التي تسترد المؤلف. يؤدي استرداد
الحقل author
إلى الاستعلام عن قاعدة البيانات. وبعد مرور بعض الوقت، تدرك أنك بحاجة إلى
عرض اسم المؤلف في واجهة المستخدم الخاصة بتطبيقك أيضًا. يمكنك الوصول إلى هذا الاسم بسهولة كافية، كما هو موضّح في مقتطف الرمز التالي:
Kotlin
authorNameTextView.text = book.author.name
Java
authorNameTextView.setText(book.getAuthor().getName());
ومع ذلك، يبدو أنّ هذا التغيير غير سليم، يؤدي إلى إنشاء طلب بحث في جدول Author
في سلسلة التعليمات الرئيسية.
إذا قمت بالاستعلام عن معلومات المؤلف مسبقًا، يصبح من الصعب تغيير
كيفية تحميل البيانات إذا لم تعد بحاجة إلى تلك البيانات. على سبيل المثال، إذا لم تعُد واجهة المستخدم لتطبيقك بحاجة إلى عرض معلومات Author
، سيحمِّل تطبيقك
البيانات التي لم يعُد يعرضها، ما يؤدي إلى إهدار مساحة قيّمة على الذاكرة. تقلّ كفاءة تطبيقك أكثر إذا كانت الفئة Author
تشير إلى جدول آخر، مثل Books
.
للإشارة إلى كيانات متعددة في نفس الوقت باستخدام Room، يمكنك بدلاً من ذلك إنشاء POJO يحتوي على كل كيان، ثم كتابة استعلام يضم الجداول المقابلة. إنّ هذا النموذج المنظّم جيدًا، إلى جانب إمكانات التحقّق من صحة طلبات البحث الفعّالة في الغرفة، يسمح لتطبيقك باستهلاك عدد أقل من الموارد عند تحميل البيانات، ما يؤدي إلى تحسين أداء تطبيقك وتجربة المستخدم.