التعامل مع قواعد البيانات باستخدام روم Room Jetpack

15 June
 مرحبا عدنا الى شروحات الترسانة JetPack و هذه المرة مع Room لادارة قاعدة البيانات بافضل طريقة ممكنة و باقل عدد من  الاخطاء قد تكون Room السلاح الاكثر قابلية  للاستعمال مع بين ترسانة Jetpack اذا سبق و حصلت على العديد من الاخطاء بسبب قاعدة البيانات الحقيرة SQLite فان  Room هو الحل  بدل التعامل cursor ستتعامل مع الكلاسات و هذا افضل و اسرع .
التعامل مع قواعد البيانات باستخدام روم Room Jetpack

1-ما هي مميزات الروم

  1. لا تسمح لك روم بان ترسل استعلاما خاطئا لقاعدة البيانات فالتحقق يتم اثناء برمجة التطبيق
  2. ستحتاج الى طلب او instance واحد لقاعدة البيانات  في كل التطبيق
  3. تتميز روم بالسرعة مقارنة مع realm
  4. تتميز بالحجم الصغير مقارنة مع realm
  5. لا يمكن الاتصال بروم من خلال thread الرئيسي و انما من خلال  thread منفصل -اختياري-

2-تهيئ البيئة :
قم باضافة روم الى ملف
build.gradle  (Module: app)
apply plugin: 'kotlin-android'
//...
dependencies {
//...
implementation "android.arch.persistence.room:runtime:1.1.1"
kapt "android.arch.persistence.room:compiler:1.1.1"
}
يمكنك معرفة اخر اصدار من المكتبة من هنا :

3- معاينة الجدول:
سنقوم بانشاء جدول به  المعرف و يجب ان يكون فريد unique  و الاسم و العمر و هكذا سيكون :
table  SQLite
+-------+--------------+------+-----+----------------+
| Field | Type         | Null | Key | Extra          |
+-------+--------------+------+-----+----------------+
| id    | int          | YES  | PRI | auto_increment |
| name  | String       | NO   |     |                |
| age   | String       | NO   |     |                |
+-------+--------------+------+-----+----------------+

4-حسنا الان الى التطبيق :
حسنا سنقوم بانشاء داتا كلاس(اساسيات كوتلن) و فيه سيكون المعرف  و الاسم و العمر :
  • @PrimaryKey : لاجل جعل المعرف خاصا و هو اجباري 
  • autoGenerate : يعني اذا كنت تريد ملىء الحقل تزايديا ضع true 
  • @ColumnInfo : وضع اسم الحقل اذا كنت ترغب فاعطائه اسما غير الاسم الموجود في الكلاس
AppDatabase.kt  (Data Class → Person)
@Entity
data class Person(@PrimaryKey(autoGenerate = true) var id:Int,
                  @ColumnInfo(name = "name") var name:String,
                  @ColumnInfo(name = "age")  var age:Double)
الان سنقوم باضافة DAO :
ما هو DAO هو كائن object يسمح لك للتحقق من صحة الاستعلام اثناء الكومبلين  حسنا بعبارة اوضح هو للوصول الى قاعدة البيانات بامان تام من اخطاء برمجية .
DAO اما ان يكون Interface او abstract  انا ساستعمل interface :
AppDatabase.kt  (Interface → PersonDao)

@Dao
interface PersonDao {
 @Query("SELECT * FROM person")
 fun getAll(): List<Person>

 @Query("SELECT * FROM person WHERE id IN (:personIds)")
 fun loadAllByIds(userIds: IntArray): List<Person>

 @Query("SELECT * FROM person WHERE name LIKE :name LIMIT 1")
 fun findByName(name: String): Person

 @Insert(onConflict = REPLACE)
 fun insertAll(vararg users: Person)
 // or fun insertAll(users: List<Person>)

 @Delete
 fun delete(user: Person)
}
ستلاحظ انه رغم ان الاستعلامات عبارة عن String الا انه يتم التحقق من  المعلومات التي فيه .
يتم استقبال القيم عبر interface و يتم اخدها من الانترفيس فقط باضافة نقطتين قبل اسم المتغير .
قابلة للتحقق
  1. @Insert لاضافة مستخدم الى قاعدة البيانات , يرجى الانتباه الى امكانية وجود تعارض conflit .
  2. @Query  لعمل استعلام على قاعدة البيانات .
  3. @Update لتحديث معلومات المستخدم على قاعدة البيانات .
  4. @Delete لحذف مستخدم على قاعدة البيانات .
لا يمكن التحقق منها.
  1. @RawQuery لاستقبال استعلامات مجهولة و  يستحق تدوينة منفردة .
 تاليا نضيف الكلاس الذي ناخد به instance من database :
AppDatabase.kt  (Main Class → AppDatabase)
@Database(entities = arrayOf(Person::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
 abstract fun personDao(): PersonDao
}

كل الكودات التالية يمكن جمعها في ملف واحد باسم  AppDatabase.kt
حسنا لننتقل الى الجهة الاخرى وهي الواجهة :
Main.kt
Main.kt  (Activity → Main)
 class Main : AppCompatActivity() {
    
     override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.ac_main)
      //استخدام مكتبة انكو لتسهيل الوصول الى تريد thread منفصل
      doAsync {
       //instance
       val db = Room.databaseBuilder(this@Main, AppDatabase::class.java, "database-name").build()
       //انشاء مستحدم جديد
       val person=Person( null, "Ismail Bella",  19.0)
       //اضافة المستخدم الى قاعدة البيانات من خلال interface
       db.userDao().insertAll(person)
       // ارسال استعلام للحصول على معلومات المستخدم المسجلة من خلال الاسم
       val rp=db.userDao().findByName("Ismail Bella")
       //طباعة عمر المستخدم على Log
       uiThread { Log.e("your age",rp.age.toString()) }
      }
     }
    }
 تجدر الاشارة الى انني استخدمت مكتبة انكو للوصول الى thread منفصل  و لابد من  طلب الوصول الى قاعدة البيانات من خلال  thread منفصل .
نتيجة التطبيق على Log
5-تخزين الكائنات :
احزر ماذا يمكن باستعمال مكتبة مثل gson تخزين List او اي كائن او نوع يحتوي على بيانات لنفترض ان لدينا Map :
val map = mapOf(1 to "x", 2 to "y", -1 to "zz")
لنقم باضافة حقل خاص ب Map الى data Class السابق Person .
@Entity
data class Person(@PrimaryKey(autoGenerate = true) var id:Int,
                  @ColumnInfo(name = "name") var name:String,
                  @ColumnInfo(name = "age")  var age:Double,
                  var map:Map<Int,String>)
ما سنقوم به الان هو اضافة مكتبةgson الى المشروع .
implementation 'com.google.code.gson:gson:2.8.5'
الان نضيف المحول من json الى ماب في/تحت ملف/كلاس PersonDoa .

class MapConverter {
 @TypeConverter
 fun fromString(value: String): Map<String,String> {
  val listType = object : TypeToken<Map<String, String>>() {

  }.type
  return Gson().fromJson(value, listType)
 }

 @TypeConverter
 fun fromList(list: Map<String,String>): String {
  val gson = Gson()
  return gson.toJson(list)
 }
}
 ثم نربطه مع Appdatabase .
@Database(entities = arrayOf(Person::class), version = 1)
@TypeConverters(MapConverter::class)
abstract class AppDatabase : RoomDatabase() {
 abstract fun personDao(): PersonDao
}
و في النهاية يمكنك تخزين القيمة في Person و روم ستتكلف بالباقي .
val map = mapOf(1 to "x", 2 to "y", -1 to "zz")
val person=Person( null, "Ismail Bella",  19.0,map)
الى هنا نكون قد انتهينا من درس اليوم .

المصادر :

هل ترغب في مثل هذه التدوينات

اسماعيل ايت بلا

ببساطة ارغب في تجربة جديدة من التعلم من خلال مشاركة ما تعلمه يجبرني ذلك على البحث لمدة طويلة مما يجعل الموقع جديرا بالثقة

اترك لنا تعليقا

الاشتراك بالقائمة البريدية

توصل باحدث مواضيعنا و كن على اطلاع باخر اخبار وتقنيات الاندرويد