Room: المفاهيم الأساسية، Entity و DAO والعمل مع قواعد البيانات

المؤلف: IT Sectr نُشر: 2026-05-04 وقت القراءة: 8 دق

Room هي مكتبة للعمل مع SQLite في Android، وهي جزء من Jetpack. توفر طبقة تجريد فوق SQLite الخام، مما يؤتمت إنشاء الجداول وتنفيذ الاستعلامات وتحويل البيانات إلى كائنات Kotlin و Java. وفقًا لـ Android Developers، يقوم Room بتجميع استعلامات SQL في وقت البناء، للتحقق من صحة النحو والعلاقات بين Entity والجداول.

الخلاصة

  • Room هي مكتبة ORM من Jetpack للعمل مع SQLite في تطبيقات Android.
  • Entity هو class مشروح بـ @Entity، كل مثيل يتوافق مع صف في جدول.
  • DAO هو كائن الوصول إلى البيانات بطرق مشروحة لاستعلامات SQL.
  • Database هو class مجرد يوسع RoomDatabase، يربط Entity و DAO.
  • الترحيل هو آلية لتغيير مخطط قاعدة البيانات بأمان دون فقدان بيانات المستخدم.

ما هو Room ولماذا هو مطلوب

Room هي مكتبة استمرارية من Android Jetpack توفر تعيينًا كائنياً-علائقياً لـ SQLite. يحل Room ثلاث مشاكل رئيسية لـ SQLite الخام: كتابة كميات كبيرة من الكود التكراري لإنشاء الجداول، عدم وجود التحقق من استعلامات SQL في وقت الترجمة، والتحويل اليدوي لـ Cursor إلى كائنات.

تستخدم المكتبة معالج الشروح (kapt أو KSP) الذي يولد تطبيق classات RoomDatabase و DAO المجردة في وقت البناء. وهذا يضمن اكتشاف الأخطاء النحوية في SQL وعدم تطابق الأنواع قبل تشغيل التطبيق، بدلاً من وقت التشغيل بعد النشر على Google Play.

وفقًا لـ Google I/O 2023، يُستخدم Room في 68% من تطبيقات Android التي تعمل مع البيانات المحلية. إنه المعيار لتخزين البيانات على الجهاز، موصى به من Google لجميع المشاريع الجديدة — بدلاً من SQLiteOpenHelper و ContentProvider القديمين.

قم بدمج Room في المشاريع التي تتطلب تخزينًا مؤقتًا محليًا للبيانات من الخادم، أو وضع عدم الاتصال، أو تخزين بيانات المستخدم المهيكلة مع إمكانية تنفيذ استعلامات SQL معقدة.

Room هو جزء من Android Jetpack وهو موصى به رسميًا من Google لجميع المشاريع الجديدة التي تعمل مع البيانات المحلية. على عكس Realm أو ObjectBox، يستخدم Room SQLite الأصلي، مما يضمن التوافق مع أي أدوات قاعدة بيانات تابعة لجهات خارجية — من DB Browser إلى DataGrip. يمكن للمطورين فتح ملف .db للتطبيق وتنفيذ استعلامات SQL مباشرة، مما يبسط التصحيح وتحليل البيانات أثناء التطوير.

Entity والشروح في Room

Entity هو class بيانات مشروح بـ @Entity يحوله Room إلى جدول قاعدة بيانات. كل حقل من class يصبح عمودًا في الجدول، وكل مثيل يصبح صفًا. يستخدم Room الانعكاس للوصول إلى الحقول، لذلك فإن الشرح @PrimaryKey مطلوب لمعرف إلزامي.

الشروح الرئيسية

الشرح @Entity يخبر Room أن class هو جدول. تحدد المعلمة tableName اسم الجدول إذا كان مختلفًا عن اسم class. @PrimaryKey يحدد المفتاح الأساسي مع دعم التوليد التلقائي عبر autoGenerate = true.

kotlin
@Entity(tableName = "users")
data class User(
    @PrimaryKey(autoGenerate = true)
    val id: Int = 0,
    @ColumnInfo(name = "full_name")
    val name: String,
    @Ignore
    val tempData: String?
)

@ColumnInfo يحدد اسم العمود في الجدول إذا كان مختلفًا عن اسم الحقل في Kotlin. @Ignore يستبعد حقلاً من الجدول — لن يتم حفظه في قاعدة البيانات. @ForeignKey يصف المفاتيح الخارجية للعلاقات بين الجداول مع عمليات التتالي عند الحذف أو التحديث.

يدعم Room الكائنات المتداخلة من خلال الشرح @Embedded. يتم توسيع حقول class المتداخل إلى أعمدة الجدول الأصلي ببادئة لتجنب تعارض الأسماء. على سبيل المثال، class Address مع حقلي city و street المضمنة في User سينشئ عمودي address_city و address_street في جدول users، مما يلغي الحاجة إلى جداول منفصلة لكائنات القيمة البسيطة.

محولات الأنواع

يدعم Room فقط الأنواع البدائية وأغلفتها. لتخزين القوائم أو Date أو الأنواع المخصصة، استخدم @TypeConverter — طرق ثابتة للتحويل بين نوع مخصص ونوع بدائي لـ SQLite، على سبيل المثال، بين List وسلسلة JSON.

DAO واستعلامات SQL

DAO (كائن الوصول إلى البيانات) هو واجهة أو class مجرد مشروح بـ @Dao يحتوي على طرق للوصول إلى البيانات. كل طريقة مشروحة بعملية SQL: @Insert أو @Update أو @Delete أو @Query مع استعلام SQL صريح.

@Query مع التحقق في وقت الترجمة

الشرح @Query يأخذ سلسلة SQL يتحقق منها Room في وقت الترجمة لصحة النحو ومطابقة أسماء الأعمدة مع حقول Entity. يدعم Room الاستعلامات المحددة المعلمات من خلال الصيغة :paramName.

kotlin
@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :userId")
    suspend fun getUserById(userId: Int): User?

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUser(user: User)

    @Query("SELECT * FROM users ORDER BY name ASC")
    fun getAllUsers(): Flow<List<User>>
}

@Insert يدعم استراتيجيات OnConflictStrategy للتعامل مع التعارضات عند إدراج سجلات مكررة. Flow كنوع إرجاع يوفر تحديثات تفاعلية لواجهة المستخدم عند كل تغيير في البيانات بالجدول — يتم إعادة تشغيل الاشتراك تلقائيًا عند أي INSERT أو UPDATE أو DELETE.

@Transaction للعمليات المعقدة

الشرح @Transaction يضمن التنفيذ الذري لعدة عمليات داخل كتلة معاملات واحدة. يقوم Room بقفل قاعدة البيانات أثناء التنفيذ، مما يمنع حالات السباق أثناء الوصول المتزامن من خيوط متعددة.

Database وترحيلات المخطط

RoomDatabase هو class مجرد يجمع Entity و DAO في نقطة وصول واحدة لقاعدة البيانات. يتم إنشاؤه عبر Room.databaseBuilder مع إصدار المخطط وقائمة classات Entity. يجب إنشاء مثيل قاعدة البيانات كمفرد باستخدام lazy delegate لتجنب الاتصالات المتعددة.

الترحيلات

الترحيل في Room هو class Migration يصف script SQL للانتقال من إصدار قديم للمخطط إلى إصدار جديد. إذا لم يتم توفير ترحيل عند تغيير المخطط، يرمي Room IllegalStateException. هذا يحمي من فقدان بيانات المستخدم العرضي عند تحديث التطبيق.

kotlin
val migration_1_2 = object : Migration(1, 2) {
    override fun migrate(db: SupportSQLiteDatabase) {
        db.execSQL("ALTER TABLE users ADD COLUMN age INTEGER NOT NULL DEFAULT 0")
    }
}

val db = Room.databaseBuilder(
    getApplication(),
    AppDatabase::class.java,
    "app_database"
).addMigrations(migration_1_2)
 .build()

للتطوير، يمكنك استخدام fallbackToDestructiveMigration، الذي يحذف قاعدة البيانات القديمة وينشئ جديدة عند عدم تطابق الإصدارات. هذا الوضع مخصص فقط للتصحيح — يجب أن تتضمن إصدارات الإنتاج ترحيلات مناسبة.

لاختبار قاعدة البيانات، يوفر Room classًا خاصًا Room.inMemoryTestBuilder الذي ينشئ قاعدة بيانات في الذاكرة دون حفظ على القرص. بعد اكتمال كل اختبار، يتم تدمير قاعدة البيانات تلقائيًا، مما يضمن عزلًا كاملًا لسيناريوهات الاختبار. بالاقتران مع مكتبة android-arch-core-testing، يمكن للمطورين إدارة دورة حياة قاعدة البيانات والتحقق من صحة الترحيلات دون الحاجة إلى تنظيف الحالة يدويًا.

يعتمد أداء Room بشكل مباشر على هيكل الاستعلامات والفهارس. لتحليل الاستعلامات البطيئة، يوفر Room العلم enableQueryCallback، الذي يسجل جميع استعلامات SQL مع وقت التنفيذ. يمكن للمطورين استخدام هذا السجل للعثور على الاستعلامات التي تستغرق أكثر من 100 مللي ثانية وتحسينها بإضافة فهارس مركبة عبر الشرح @Index في @Entity أو إعادة كتابة الاستعلامات الفرعية كعمليات JOIN مباشرة باستخدام @Relation.

يدعم Room أيضًا تشفير قاعدة البيانات عبر SQLCipher. إضافة مكتبة net.zetetic:android-database-sqlcipher واستخدام SupportFactory بدلاً من المعيارية يوفر تشفيرًا شفافًا لجميع البيانات على القرص دون تغيير استعلامات DAO أو هيكل Entity. هذا ضروري للتطبيقات التي تتعامل مع بيانات المستخدم الشخصية ويتوافق مع GDPR والقانون الفيدرالي الروسي 152-FZ بشأن حماية البيانات الشخصية. يمكن تخزين كلمة مرور التشفير في Android Keystore للحماية من الاستخراج عبر الأدوات على الأجهزة المجذرة.

Room مع Kotlin Coroutines و Flow

Room يدعم Kotlin Coroutines بشكل أصلي بدءًا من الإصدار 2.1. يمكن أن تكون طرق DAO دوال suspend تنفذ الاستعلامات في الخلفية دون حظر الخيط الرئيسي. يدير Room الموزعين تلقائيًا، باستخدام Dispatchers.IO لاستعلامات القراءة والكتابة.

للاستعلامات التفاعلية، يُرجع Room Flow — تدفق بيانات بارد يصدر قيمة جديدة عند كل تغيير في الجدول المتأثر. يشترك ViewModel في Flow عبر stateIn أو collect، مما يوفر تحديثات تلقائية لواجهة المستخدم دون إخطار المحول يدويًا.

يدعم Room أيضًا Paging 3 من خلال تطبيق PagingSource خاص يقوم بتحميل البيانات صفحة بصفحة من SQLite. هذا فعال للقوائم الكبيرة بآلاف السجلات: Paging 3 يحمل فقط الصفوف المرئية على الشاشة ويحدثها تلقائيًا عند تغييرات قاعدة البيانات.

استخدم Paging 3 مع Room لعرض خلاصات الأخبار وسجلات العمليات أو قوائم المنتجات مع الوصول دون اتصال والتمرير اللانهائي.

الأسئلة الشائعة

ما الفرق بين Room و SQLiteOpenHelper؟

Room يؤتمت إنشاء الجداول وتحويل Cursor إلى كائنات والتحقق من SQL في وقت الترجمة. SQLiteOpenHelper يتطلب كتابة المخطط يدويًا ومعالجة Cursor وليس لديه التحقق من الاستعلامات قبل تشغيل التطبيق، مما يزيد من خطر الأخطاء.

هل أحتاج إلى كتابة ترحيلات لكل تغيير في المخطط؟

نعم، عند تغيير Entity (إضافة/إزالة حقل، تغيير نوع)، يلزم الترحيل. بدونه، يرمي Room IllegalStateException عند بدء التشغيل. للتطوير، يمكنك تمكين fallbackToDestructiveMigration، لكن إصدارات الإنتاج تتطلب scripts ترحيل صحيحة.

هل يدعم Room العلاقات بين الجداول؟

يدعم Room @ForeignKey للعمليات المتتالية و @Relation للكائنات المتداخلة. للاستعلامات JOIN المعقدة، استخدم الشرح @Transaction مع @Query الذي يعيد POJO بكيانات متداخلة عبر @Embedded و @Relation.

هل يمكنني استخدام Room مع Java بدون Kotlin؟

نعم، Room متوافق تمامًا مع Java. بدلاً من دوال suspend، استخدم LiveData أو RxJava Observable؛ بدلاً من Flow، استخدم LiveData. Room مع Java يدعم جميع الشروح نفسها، لكنه يتطلب المزيد من الكود التكراري للعمليات غير المتزامنة.

كيف يعمل تشفير قاعدة بيانات Room؟

يدعم Room التشفير عبر SQLCipher من Zetetic. بدلاً من Room.databaseBuilder، استخدم SupportFactory من مكتبة net.zetetic:android-database-sqlcipher، مع تمرير كلمة مرور التشفير. سيتم تشفير جميع البيانات على القرص بشفافية لاستعلامات DAO.

الملخص

  • Room هي مكتبة ORM من Jetpack لـ SQLite مع التحقق من SQL في وقت الترجمة.
  • @Entity يصف الجدول، @PrimaryKey هو المعرف، @ColumnInfo هو اسم العمود.
  • @Dao يحتوي على طرق مع @Query و @Insert و @Update و @Delete للوصول إلى البيانات.
  • RoomDatabase يجمع Entity و DAO، يتم إنشاؤه عبر Room.databaseBuilder.
  • الترحيلات (Migration) تصف scripts SQL لتغييرات المخطط دون فقدان البيانات.
  • يدعم Room Kotlin Coroutines (suspend) و Flow بشكل أصلي للتحديثات التفاعلية لواجهة المستخدم.
  • للقوائم الكبيرة، استخدم Paging 3 مع Room عبر PagingSource للتحميل المقسم إلى صفحات.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا