SQLite (Kotlin Multiplatform)

تحتوي مكتبة androidx.sqlite على واجهات مجرّدة بالإضافة إلى عمليات تنفيذ أساسية يمكن استخدامها لإنشاء مكتباتك الخاصة التي يمكنها الوصول إلى SQLite. ننصحك باستخدام مكتبة Room التي توفّر طبقة تجريد فوق SQLite للسماح بالوصول إلى قاعدة البيانات بشكل أكثر فعالية مع الاستفادة من إمكانات SQLite الكاملة.

إعداد التبعيات

لإعداد SQLite في مشروع KMP، أضِف التبعيات الخاصة بالعناصر في ملف build.gradle.kts للوحدة النمطية:

[versions]
sqlite = "2.5.2"

[libraries]
# The SQLite Driver interfaces
androidx-sqlite = { module = "androidx.sqlite:sqlite", version.ref = "sqlite" }

# The bundled SQLite driver implementation
androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" }

[plugins]
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }

واجهات برمجة التطبيقات لبرنامج تشغيل SQLite

تقدّم مجموعات مكتبة androidx.sqlite واجهات برمجة تطبيقات منخفضة المستوى للتواصل مع مكتبة SQLite، سواء كانت مضمّنة في المكتبة عند استخدام androidx.sqlite:sqlite-bundled أو في النظام الأساسي المضيف، مثل Android أو iOS، عند استخدام androidx.sqlite:sqlite-framework. تتّبع واجهات برمجة التطبيقات هذه الوظائف الأساسية لواجهة برمجة التطبيقات C في SQLite.

هناك 3 واجهات رئيسية:

  • SQLiteDriver: هي نقطة الدخول لاستخدام SQLite، وهي مسؤولة عن فتح اتصالات قواعد البيانات.
  • SQLiteConnection: هو تمثيل العنصر sqlite3.
  • SQLiteStatement: هو تمثيل العنصر sqlite3_stmt.

يعرض المثال التالي واجهات برمجة التطبيقات الأساسية:

fun main() {
  val databaseConnection = BundledSQLiteDriver().open("todos.db")
  databaseConnection.execSQL(
    "CREATE TABLE IF NOT EXISTS Todo (id INTEGER PRIMARY KEY, content TEXT)"
  )
  databaseConnection.prepare(
    "INSERT OR IGNORE INTO Todo (id, content) VALUES (? ,?)"
  ).use { stmt ->
    stmt.bindInt(index = 1, value = 1)
    stmt.bindText(index = 2, value = "Try Room in the KMP project.")
    stmt.step()
  }
  databaseConnection.prepare("SELECT content FROM Todo").use { stmt ->
    while (stmt.step()) {
      println("Action item: ${stmt.getText(0)}")
    }
  }
  databaseConnection.close()
}

على غرار واجهات برمجة التطبيقات C في SQLite، يتمثل الاستخدام الشائع في ما يلي:

  • افتح اتصالاً بقاعدة بيانات باستخدام التنفيذ الذي تم إنشاء مثيل له SQLiteDriver.
  • إعداد عبارة SQL باستخدام SQLiteConnection.prepare()
  • نفِّذ SQLiteStatement بالطريقة التالية:
    1. يمكنك ربط الوسيطات اختياريًا باستخدام دوال bind*().
    2. كرِّر مجموعة النتائج باستخدام الدالة step().
    3. قراءة الأعمدة من مجموعة النتائج باستخدام دوال get*()

عمليات تنفيذ برامج التشغيل

يلخّص الجدول التالي عمليات تنفيذ برامج التشغيل المتاحة:

اسم الصف

العناصر

الأنظمة الأساسية المتوافقة

AndroidSQLiteDriver androidx.sqlite:sqlite-framework

Android

NativeSQLiteDriver androidx.sqlite:sqlite-framework

iOS وMac وLinux

BundledSQLiteDriver androidx.sqlite:sqlite-bundled

‫Android وiOS وMac وLinux وJVM (أجهزة الكمبيوتر)

ننصح باستخدام BundledSQLiteDriver المتوفّرة في androidx.sqlite:sqlite-bundled. وتتضمّن مكتبة SQLite التي تم تجميعها من المصدر، ما يوفّر أحدث إصدار وتوافقًا على جميع منصات KMP المتوافقة.

برنامج تشغيل SQLite وRoom

تكون واجهات برمجة التطبيقات الخاصة ببرامج التشغيل مفيدة للتفاعلات المنخفضة المستوى مع قاعدة بيانات SQLite. ننصح باستخدام Room إذا كنت تريد مكتبة تتضمّن العديد من الميزات وتوفّر إمكانية وصول أكثر فعالية إلى SQLite.

تعتمد RoomDatabase على SQLiteDriver لتنفيذ عمليات قاعدة البيانات، ويجب ضبط عملية التنفيذ باستخدام RoomDatabase.Builder.setDriver(). توفّر الفئة Room RoomDatabase.useReaderConnection و RoomDatabase.useWriterConnection للوصول بشكل مباشر إلى اتصالات قاعدة البيانات المُدارة.

نقل البيانات إلى Kotlin Multiplatform

يجب نقل أي استخدام لطلبات SQLite منخفضة المستوى إلى نظيراتها في SQLite Driver.

‫Kotlin Multiplatform

إجراء معاملة باستخدام SQLiteConnection منخفض المستوى

val connection: SQLiteConnection = ...
connection.execSQL("BEGIN IMMEDIATE TRANSACTION")
try {
  // perform database operations in transaction
  connection.execSQL("END TRANSACTION")
} catch(t: Throwable) {
  connection.execSQL("ROLLBACK TRANSACTION")
}

تنفيذ طلب بحث بدون نتيجة

val connection: SQLiteConnection = ...
connection.execSQL("ALTER TABLE ...")

تنفيذ طلب بحث يتضمّن نتيجة ولكن بدون وسيطات

val connection: SQLiteConnection = ...
connection.prepare("SELECT * FROM Pet").use { statement ->
  while (statement.step()) {
    // read columns
    statement.getInt(0)
    statement.getText(1)
  }
}

تنفيذ طلب بحث مع نتيجة ووسيطات

connection.prepare("SELECT * FROM Pet WHERE id = ?").use { statement ->
  statement.bindInt(1, id)
  if (statement.step()) {
    // row found, read columns
  } else {
    // row not found
  }
}

على أجهزة Android فقط

إجراء معاملة باستخدام SupportSQLiteDatabase

val database: SupportSQLiteDatabase = ...
database.beginTransaction()
try {
  // perform database operations in transaction
  database.setTransactionSuccessful()
} finally {
  database.endTransaction()
}

تنفيذ طلب بحث بدون نتيجة

val database: SupportSQLiteDatabase = ...
database.execSQL("ALTER TABLE ...")

تنفيذ طلب بحث يتضمّن نتيجة ولكن بدون وسيطات

val database: SupportSQLiteDatabase = ...
database.query("SELECT * FROM Pet").use { cursor ->
  while (cusor.moveToNext()) {
    // read columns
    cursor.getInt(0)
    cursor.getString(1)
  }
}

تنفيذ طلب بحث مع نتيجة ووسيطات

database.query("SELECT * FROM Pet WHERE id = ?", id).use { cursor ->
  if (cursor.moveToNext()) {
    // row found, read columns
  } else {
    // row not found
  }
}