Home > Software engineering >  Prepopulate Room database build success and no error tip ,But the prepopulate data not add to the da
Prepopulate Room database build success and no error tip ,But the prepopulate data not add to the da

Time:08-11

Room 2.5.0-alpha02

I need the prepopulate one table data to the database , So I make a .db file only have one table which I need inflate the prepopulate data , The Android developer document told 2.4.0 Room have auto migrate ,and So I not write the migrate code . But when I build and run app, the data not add to the app database.

DataBase.kt

I add the fallbackToDestructiveMigration , and the app db version is higher one than the .db file

@Database(
    entities = [DetectAd::class, DetectResult::class, DetectItem::class],
    exportSchema = false,
    version = 2
)
@TypeConverters(Converter::class)
abstract class AppDatabase : RoomDatabase() {
    abstract fun detectItemDao(): DetectItemDao

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
          
            return INSTANCE ?: synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "app_db.db"
                )
                    .createFromAsset("database/appDatabase2.db")
                    .fallbackToDestructiveMigration()
                    .build()
                INSTANCE = instance
                // return instance
                instance
            }
        }

    }

appDatabase2.db file

enter image description here

App db after run The prepopulate data not inflate to the db enter image description here

So, should I make a complete prepopulate .db file which struct 100% same like the app db struct, although I only want to prepoulate one table data? If not ,what i need do ?

Thanks for your help.


Additional remarks

When I make the app db version to one (same to file) , app hava a error tip:

 java.lang.IllegalStateException: Pre-packaged database has an invalid schema: detectAd(com.sunbio.coagulation.data.db.entity.DetectAd).
     Expected:
    TableInfo{name='detectAd', columns={Ad4=Column{name='Ad4', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad3=Column{name='Ad3', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad6=Column{name='Ad6', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad5=Column{name='Ad5', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad8=Column{name='Ad8', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad7=Column{name='Ad7', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, adNo=Column{name='adNo', type='INTEGER', affinity='3', notNull=notNull, primaryKeyPosition=1, defaultValue='null'}, sampleNo=Column{name='sampleNo', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, time=Column{name='time', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad2=Column{name='Ad2', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}, Ad1=Column{name='Ad1', type='TEXT', affinity='2', notNull=notNull, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
     Found:
    TableInfo{name='detectAd', columns={}, foreignKeys=[], indices=[]}
        at androidx.room.RoomOpenHelper.checkIdentity(RoomOpenHelper.kt:159)
        at androidx.room.RoomOpenHelper.onOpen(RoomOpenHelper.kt:128)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onOpen(FrameworkSQLiteOpenHelper.java:326)
        at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:409)
        at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:298)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableOrReadableDatabase(FrameworkSQLiteOpenHelper.java:273)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.innerGetDatabase(FrameworkSQLiteOpenHelper.java:225)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getSupportDatabase(FrameworkSQLiteOpenHelper.java:183)
        at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:133)
        at androidx.room.SQLiteCopyOpenHelper.getWritableDatabase(SQLiteCopyOpenHelper.kt:71)
        at androidx.room.RoomDatabase.inTransaction(RoomDatabase.kt:634)
        at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.kt:430)
        at com.sunbio.coagulation.data.db.dao.DetectItemDao_Impl.getAllName(DetectItemDao_Impl.java:270)
        at com.sunbio.coagulation.ui.manager.DetectManagerFragment$getData$1$1.invokeSuspend(DetectManagerFragment.kt:196)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.internal.LimitedDispatcher.run(LimitedDispatcher.kt:42)
        at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:95)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)

CodePudding user response:

In the image of the pre-populated database the table name is detectItem Room expects a table named detectAd (and more).

The pre-populated database MUST HAVE the same tables (others will be ignored) as Room expects. The tables MUST HAVE the same columns that Room expects.

  • see below re prePackagedDatabaseCallback as an alternative resolution.

e.g. You don't appear to have a column Ad4 in the image, so just renaming detectItem to detectAd will result in yet another Expect .... Found ... error.

What Room expects is determined by the @Entity annotated classes that are in the list of entities coded in the @Database annotation.

  • from the message/log Room expects a column named Ad4 that is a type of TEXT

I would suggest that after you have created the @Entity classes and specified them in the @Database annotated class via the entities parameters of the @Database` annotation that you then use the SQL that Room generates.

The SQl is generated when you compile (Make the project).

This SQL can be found in the generated java (visible via Android View) in the createAlltable method class that is named the same as the @Database annotated class but suffixed with _Impl.

You do not need to create the room_master_table as this will be created by Room.

So, should I make a complete prepopulate .db file which struct 100% same like the app db struct, although I only want to prepoulate one table data? If not ,what i need do ?

YES (unless:-)

  • the alternative could be to utilise the prePackagedDatabaseCallback, in which case you could create the tables and then copy data from the detectItem table (that should exist as the callback is called when after the pre-packaged database has been copied from the assets)

    • again I strongly suggest using the SQL generated when you compile the App, Room is very particular in what it expects.
      • The link given below, covers the steps of copying the generated SQL.
  • when the processing is finished in the callback then Room continues in it's attempt to open the database checking that the schema is as expected (i.e the end result MUST be a schema that Room expects).

  • you may find this Question/Answer useful if this is how you want to proceed.

  • note I'm unsure about how, or if, Room manages prepackaged with subsequent migrations. However, I would suggest that it would be most prudent to not use the callback, but to always alter the prepackaged database (i.e. change the asset file accordingly).

    • doing so has the added benefit of being a test of the migration (or at least the SQL aspect of the migration, which will typically be all of the migration).
  • Related