Search code examples
androidandroid-roomauto-migration

Room Database Migration Issue - TableInfo Columns Not Matching


I am experiencing a crash in my Android application due to an issue with Room database migration. The crash log indicates that the migration didn't properly handle the BROADCAST_LIST table. Below is the relevant portion of the crash log:

java.lang.IllegalStateException: Migration didn't properly handle: BROADCAST_LIST(com.enjayworld.enjaycrm.broadcastAutomation.data.model.PhoneNumber).
Expected:
TableInfo{name='BROADCAST_LIST', columns={date=Column{name='date', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='CURRENT_TIMESTAMP'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}, verification_status=Column{name='verification_status', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, phone=Column{name='phone', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, isWhatsApp=Column{name='isWhatsApp', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, file_name=Column{name='file_name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='BROADCAST_LIST', columns={}, foreignKeys=[], indices=[]}
    at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.kt:93)
    at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.kt:253)
    at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:416)
    at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
    at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableOrReadableDatabase(FrameworkSQLiteOpenHelper.kt:232)
    at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.innerGetDatabase(FrameworkSQLiteOpenHelper.kt:190)
    at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getSupportDatabase(FrameworkSQLiteOpenHelper.kt:151)
    at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.kt:104)
    at androidx.room.RoomDatabase.inTransaction(RoomDatabase.kt:632)
    at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.kt:451)

Has anyone encountered a similar issue or have any advice on how to resolve this migration problem? Any help would be greatly appreciated!

I want to figure out the rootcasue of this issue and how can i fix this


Solution

  • As per the message, after the Migration the table BROADCAST_LIST does not meet the expectations of Room.

    As there are no columns found, the table itself has not been found (see mock-up/demo below). You need to ensure that the migration creates the table BROADCAST_LIST and that the table has the columns as expected by Room.

    The simplest and most accurate way is to utilise the SQL that Room itself builds.

    • Note that the @Entity annotated class(es) should be included in the list as per the entities parameter of the @Database annotation and that the project is successfully compiled.

      • i.e. Room generates the underlying java code based upon the @Database annotation and the @Entity annotated classes defined therein.

    This SQL can be found in the java (generated) folder available in the android view. It will be in a member/class/file that is the same name as the @Database annotated class but suffixed with _Impl. It will be in the createAllTables method/function.

    e.g. (from a mock-up of what can be ascertained from the question):-

    enter image description here

    • the highlighted line being the respective line in the mock-up

    The mock-up/demo mentioned includes the migration as per:-

                    .addMigrations(Migration(1,2){
                        Log.d("DBINFO","Migration 1 to 2 Invoked")
                        /*
                        it.execSQL("CREATE TABLE IF NOT EXISTS `BROADCAST_LIST` (`date` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP, `id` INTEGER, `verification_status` TEXT NOT NULL, `phone` TEXT NOT NULL, `isWhatsApp` INTEGER NOT NULL, `file_name` TEXT NOT NULL, PRIMARY KEY(`id`))")
    
                         */
                    })
                    .build()
    
    • noting that the execSQL statement is commented out. Running this when the migration is required (i.e. the Migration does nothing) then the resultant exception is

    :-

    2024-05-25 07:18:50.535 10384-10384/a.a.so78527078kotlinroommigrationexample E/AndroidRuntime: FATAL EXCEPTION: main
        Process: a.a.so78527078kotlinroommigrationexample, PID: 10384
        java.lang.RuntimeException: Unable to start activity ComponentInfo{a.a.so78527078kotlinroommigrationexample/a.a.so78527078kotlinroommigrationexample.MainActivity}: java.lang.IllegalStateException: Migration didn't properly handle: BROADCAST_LIST(a.a.so78527078kotlinroommigrationexample.BROADCAST_LIST).
         Expected:
        TableInfo{name='BROADCAST_LIST', columns={date=Column{name='date', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='CURRENT_TIMESTAMP'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='undefined'}, verification_status=Column{name='verification_status', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, phone=Column{name='phone', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, isWhatsApp=Column{name='isWhatsApp', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, file_name=Column{name='file_name', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}}, foreignKeys=[], indices=[]}
         Found:
        TableInfo{name='BROADCAST_LIST', columns={}, foreignKeys=[], indices=[]}
    

    When the Migration is changed to include the execSQL statement (i.e. the SQL as copied from the generated java) then (Database displayed via App Inspection):-

    enter image description here