אם רוצים שהאפליקציה תתחיל עם מסד נתונים שכבר טעון עם מערך נתונים ספציפי, אפשר לאכלס מראש את מסד הנתונים. ב-Room, אפשר להשתמש בממשקי API כדי לאכלס מראש מסד נתונים באתחול עם תוכן מקובץ מסד נתונים ארוז מראש במערכת הקבצים של המכשיר.
מילוי מראש מנכס אפליקציה
כדי לאכלס מראש מסד נתונים של Room מקובץ מסד נתונים ארוז מראש שנמצא בכל מקום בספרייה assets/ של האפליקציה, צריך לקרוא לפונקציה createFromAsset מהאובייקט RoomDatabase.Builder לפני שקוראים לפונקציה build:
Room.databaseBuilder<AppDatabase>(appContext, "sample.db") .createFromAsset("database/myapp.db") .build()
הפונקציה createFromAsset מקבלת ארגומנט מחרוזת שמכיל נתיב יחסי מהספרייה assets/ לקובץ מסד הנתונים שנארז מראש.
מילוי מראש ממערכת הקבצים
כדי לאכלס מראש מסד נתונים של Room מקובץ מסד נתונים מוכן מראש שנמצא בכל מקום במערכת הקבצים של המכשיר חוץ בספרייה assets/ של האפליקציה, צריך לקרוא לפונקציה createFromFile מהאובייקט RoomDatabase.Builder לפני שקוראים לפונקציה build:
Room.databaseBuilder<AppDatabase>(appContext, "sample.db") .createFromFile(File("mypath")) .build()
הפונקציה createFromFile מקבלת ארגומנט File עבור קובץ מסד הנתונים שהוכן מראש. Room יוצר עותק של הקובץ שצוין במקום לפתוח אותו ישירות, לכן חשוב לוודא שלאפליקציה יש הרשאות קריאה בקובץ.
טיפול בהעברות שכוללות מסדי נתונים מוכנים מראש
קובצי מסד נתונים מוכנים מראש יכולים גם לשנות את האופן שבו מסד הנתונים של Room מטפל בהעברות חזרה. בדרך כלל, כשמופעלות מיגרציות הרסניות וספריית Room צריכה לבצע מיגרציה ללא נתיב מיגרציה, ספריית Room משמיטה את כל הטבלאות במסד הנתונים ויוצרת מסד נתונים ריק עם הסכימה שצוינה לגרסת היעד. עם זאת, אם כוללים קובץ מסד נתונים ארוז מראש עם אותו מספר כמו גרסת היעד, Room מאכלס את מסד הנתונים שנוצר מחדש עם התוכן של קובץ מסד הנתונים הארוז מראש אחרי ביצוע ההעברה ההרסנית.
מידע נוסף על העברת נתונים של מסד נתונים של Room זמין במאמר העברת מסד נתונים של Room.
בקטעים הבאים מפורטות כמה דוגמאות שממחישות איך זה עובד בפועל.
דוגמה: העברה חלופית עם מסד נתונים מוכן מראש
נניח את הדברים הבאים:
- האפליקציה שלך מגדירה מסד נתונים של Room בגרסה 3.
- מופע מסד הנתונים שכבר מותקן במכשיר הוא בגרסה 2.
- יש קובץ מסד נתונים מוכן מראש בגרסה 3.
- אין נתיב העברה מוטמע מגרסה 2 לגרסה 3.
- ההעברות ההרסניות מופעלות.
// Database class definition declaring version 3. @Database(entities = [SampleEntity::class], version = 3) abstract class FallbackAppDatabase : RoomDatabase() { // ... } fun createFallbackDb(appContext: Context) { Room.databaseBuilder<FallbackAppDatabase>(appContext, "sample.db") .createFromAsset("database/myapp.db") .fallbackToDestructiveMigration() .build() }
זה מה שקורה במצב הזה:
- כי מסד הנתונים שמוגדר באפליקציה הוא בגרסה 3, ומופע מסד הנתונים שכבר מותקן במכשיר הוא בגרסה 2, ולכן נדרשת העברה.
- מכיוון שלא הוטמעה תוכנית העברה מגרסה 2 לגרסה 3, ההעברה היא העברה חלופית.
- ההעברה חזרה היא הרסנית כי קוראים לפונקציית הבנייה
fallbackToDestructiveMigration. Room משחררת את מופע מסד הנתונים שמותקן במכשיר. - מכיוון שיש קובץ מסד נתונים מוכן מראש בגרסה 3, Room יוצר מחדש את מסד הנתונים ומאכלס אותו באמצעות התוכן של קובץ מסד הנתונים המוכן מראש. אם קובץ מסד הנתונים הארוז מראש הוא בגרסה 2, Room קובעת שהוא לא תואם לגרסת היעד ולא משתמשת בו להעברה חלופית.
דוגמה: הטמעה של העברה עם מסד נתונים מוכן מראש
נניח שהאפליקציה שלכם מטמיעה נתיב העברה מגרסה 2 לגרסה 3:
// Database class definition declaring version 3. @Database(entities = [SampleEntity::class], version = 3) abstract class ImplementedAppDatabase : RoomDatabase() { // ... } // Migration path definition from version 2 to version 3. val MIGRATION_2_3 = object : Migration(2, 3) { override suspend fun migrate(connection: SQLiteConnection) { // ... } } fun createImplementedDb(appContext: Context) { Room.databaseBuilder<ImplementedAppDatabase>(appContext, "sample.db") .createFromAsset("database/myapp.db") .addMigrations(MIGRATION_2_3) .build() }
זה מה שקורה במצב הזה:
- כי מסד הנתונים שמוגדר באפליקציה הוא בגרסה 3, ומסד הנתונים שכבר מותקן במכשיר הוא בגרסה 2, ולכן נדרשת העברה.
- מכיוון שיש נתיב העברה מגרסה 2 לגרסה 3, Room מפעילה את הפונקציה
migrateשמוגדרת כדי לעדכן את מופע מסד הנתונים במכשיר לגרסה 3, תוך שמירה על הנתונים שכבר נמצאים במסד הנתונים. Room לא משתמש בקובץ מסד הנתונים שמוכן מראש, כי Room משתמש בקבצים כאלה רק במקרה של חזרה לגרסה קודמת של העברה.
דוגמה: העברה רב-שלבית עם מסד נתונים מוכן מראש
קבצים של מסדי נתונים מוכנים מראש יכולים גם להשפיע על העברות שכוללות כמה שלבים. לדוגמה:
- האפליקציה שלך מגדירה מסד נתונים של Room בגרסה 4.
- מופע מסד הנתונים שכבר מותקן במכשיר הוא בגרסה 2.
- יש קובץ מסד נתונים מוכן מראש בגרסה 3.
- יש נתיב העברה מוטמע מגרסה 3 לגרסה 4, אבל לא מגרסה 2 לגרסה 3.
- ההעברות ההרסניות מופעלות.
// Database class definition declaring version 4. @Database(entities = [SampleEntity::class], version = 4) abstract class MultiStepAppDatabase : RoomDatabase() { // ... } val MIGRATION_3_4 = object : Migration(3, 4) { override suspend fun migrate(connection: SQLiteConnection) { // ... } } fun createMultiStepDb(appContext: Context) { Room.databaseBuilder<MultiStepAppDatabase>(appContext, "sample.db") .createFromAsset("database/myapp.db") .addMigrations(MIGRATION_3_4) .fallbackToDestructiveMigration() .build() }
זה מה שקורה במצב הזה:
- כי מסד הנתונים שמוגדר באפליקציה הוא בגרסה 4, ומופע מסד הנתונים שכבר מותקן במכשיר הוא בגרסה 2, ולכן נדרשת העברה.
- מכיוון שאין נתיב העברה מוטמע מגרסה 2 לגרסה 3, ההעברה היא העברה חלופית.
- ההעברה חזרה היא הרסנית כי קוראים לפונקציית הבנייה
fallbackToDestructiveMigration. Room מפיל את מופע מסד הנתונים במכשיר. - מכיוון שיש קובץ מסד נתונים מוכן מראש בגרסה 3, Room יוצר מחדש את מסד הנתונים ומאכלס אותו באמצעות התוכן של קובץ מסד הנתונים המוכן מראש.
- מסד הנתונים שמותקן במכשיר הוא עכשיו בגרסה 3. כי היא עדיין נמוכה מהגרסה שמוגדרת באפליקציה, ולכן צריך לבצע העברה נוספת.
- מכיוון שיש נתיב העברה מגרסה 3 לגרסה 4, Room מפעיל את הפונקציה
migrateשהוגדרה כדי לעדכן את מופע מסד הנתונים במכשיר לגרסה 4, תוך שמירה על הנתונים שהועתקו מקובץ מסד הנתונים שהגיע מראש עם גרסה 3.