מעבר מ-SQLite לחדר

לשימוש בספריית Room persistence יש כמה יתרונות לעומת שימוש ישיר בממשקי ה-API של SQLite:

  • אימות של שאילתות SQL בזמן ההידור
  • הערות נוחות שמצמצמות חזרות על קוד סטנדרטי שנוטה לשגיאות
  • נתיבי העברה יעילים של מסדי נתונים

אם באפליקציה שלכם יש הטמעה של SQLite שאינה Room, כדאי לקרוא את הדף הזה כדי ללמוד איך להעביר אותה ל-Room. אם Room היא ההטמעה הראשונה של SQLite באפליקציה, כדאי לעיין במאמר שמירת נתונים במסד נתונים מקומי באמצעות Room כדי לקבל מידע על שימוש בסיסי.

שלבים בהעברה

כדי להעביר את ההטמעה של SQLite ל-Room, מבצעים את השלבים הבאים. אם ההטמעה של SQLite משתמשת במסד נתונים גדול או בשאילתות מורכבות, יכול להיות שתעדיפו לעבור ל-Room בהדרגה. מידע נוסף על אסטרטגיית העברה מצטברת זמין במאמר העברה מצטברת.

עדכון יחסי תלות

כדי להשתמש ב-Room באפליקציה, צריך לכלול את יחסי התלות המתאימים בקובץ build.gradle של האפליקציה. מידע נוסף על יחסי תלות בחדרים זמין במאמר הגדרה.

עדכון של מחלקות מודלים לישויות נתונים

‫Room משתמשת בישויות נתונים כדי לייצג את הטבלאות במסד הנתונים. כל מחלקת ישויות מייצגת טבלה, ויש לה מאפיינים שמייצגים עמודות בטבלה הזו. כדי לעדכן את מחלקות המודלים הקיימות כך שיהפכו לישויות של Room:

  1. מוסיפים את ההערה @Entity להצהרת המחלקה כדי לציין שמדובר בישות Room. אפשר להשתמש במאפיין tableName כדי לציין שלטבלה שנוצרת צריך להיות שם ששונה משם המחלקה.
  2. מוסיפים את ההערה @PrimaryKey למאפיין של המפתח הראשי.
  3. אם רוצים שלעמודות מסוימות בטבלה שמתקבלת יהיה שם שונה משם המאפיין המתאים, צריך להוסיף למאפיין את ההערה @ColumnInfo ולהגדיר את המאפיין name לשם העמודה הנכון.
  4. אם למחלקה יש מאפיינים שאתם לא רוצים לשמור במסד הנתונים, צריך להוסיף להם את ההערה @Ignore כדי לציין ש-Room לא צריך ליצור עבורם עמודות בטבלה המתאימה.
  5. אם למחלקה יש יותר מקונסטרוקטור אחד, צריך לציין באיזה קונסטרוקטור Room צריך להשתמש באמצעות הוספת ההערה @Ignore לכל שאר הקונסטרוקטורים.

@Entity(tableName = "users")
data class User(
    @PrimaryKey @ColumnInfo(name = "userid") val id: String,
    @ColumnInfo(name = "username") val userName: String?,
    @ColumnInfo(name = "last_update") val date: Date?,
)

יצירת ארגונים אוטונומיים מבוזרים (DAO)

‫Room משתמש באובייקטים של גישה לנתונים (DAO) כדי להגדיר פונקציות שמאפשרות גישה למסד הנתונים. כדי להחליף את פונקציות השאילתה הקיימות ב-DAO, פועלים לפי ההנחיות במאמר גישה לנתונים באמצעות Room DAO.

יצירת מחלקה של מסד נתונים

הטמעות של Room משתמשות במחלקת מסד נתונים כדי לנהל מופע של מסד הנתונים. מחלקת מסד הנתונים צריכה להרחיב את RoomDatabase ולהפנות לכל הישויות ולכל אובייקטי ה-DAO שהגדרתם.

@Database(entities = [User::class], version = 2)
@ColumnTypeConverters(DateConverter::class)
abstract class UsersDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

הגדרת נתיב העברה

מספר הגרסה של מסד הנתונים משתנה, ולכן צריך להגדיר אובייקט Migration כדי לשמור את הנתונים הקיימים במסד הנתונים. אם סכימת מסד הנתונים לא משתנה, יכול להיות שההעברה הזו תהיה ריקה.

val MIGRATION_1_2 = object : Migration(1, 2) {
    override suspend fun migrate(connection: SQLiteConnection) {
        // Empty implementation, because the schema isn't changing.
    }
}

מידע נוסף על נתיבי העברת נתונים של מסדי נתונים ב-Room זמין במאמר בנושא העברת מסד הנתונים.

עדכון של יצירת מופע של מסד הנתונים

אחרי שמגדירים מחלקה של מסד נתונים ונתיב העברה, אפשר להשתמש ב-Room.databaseBuilder כדי ליצור מופע של מסד הנתונים עם נתיב ההעברה שהוגדר:

val db =
    Room.databaseBuilder<UsersDatabase>(applicationContext, "database-name")
        .addMigrations(MIGRATION_1_2)
        .build()

בדיקת ההטמעה

חשוב לבדוק את ההטמעה החדשה של החדר:

העברה מצטברת

אם האפליקציה שלכם משתמשת במסד נתונים גדול ומורכב, יכול להיות שלא יהיה מעשי להעביר את האפליקציה ל-Room בבת אחת. במקום זאת, אתם יכולים ליישם את ישויות הנתונים ואת מסד הנתונים של Room כשלב ראשון, ואז להעביר את פונקציות השאילתה שלכם ל-DAO מאוחר יותר.

כדי להטמיע העברה מצטברת, צריך לקבל SupportSQLiteDatabaseעטיפת תאימות באמצעות פונקציית התוסף roomDatabase.getSupportWrapper מתוך ארטיפקט androidx.room3:room3-sqlite-wrapper. העטיפה הזו מאפשרת להריץ שאילתות SQL ישירות בסגנון Android במסד הנתונים שמנוהל על ידי Room באמצעות ממשקי Android SQLite API:

// Get SupportSQLiteDatabase wrapper
val legacyDb = roomDatabase.getSupportWrapper()
legacyDb.execSQL("INSERT INTO users ...")