Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion on Room Auto Migration with NOT NULL column but no defalut value

Short Version

After updating Android-Room version from 2.2.x to 2.4.x, I decide to use auto-migration feature to help me write less code. So I want to deprecate all migration written manually and use auto-migration instead. But I have got an error when using auto-migration:

// Compile Time Error: 
// New NOT NULL column'height' added with no default value specified. 
// Please specify the default value using @ColumnInfo.

@ColumnInfo(name = "height")
val height: Long = 0L

Even if I have specify default value by this way, but still get same error:

@ColumnInfo(name = "height", defaultValue = "0")
val height: Long = 0L

What wrong with my code and how can I fix this error?

Long Version

I have two version database:

Version 1

@Entity(tableName = "user")
data class User(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    val id: Long = 0L,
    @ColumnInfo(name = "name")
    val name: String = ""
)

@Database(
    entities = [User::class],
    version = 1
)
abstract class UserDB : RoomDatabase()

then at version 2 I add a column which name is 'height' in user table:

Version 2

@Entity(tableName = "user")
data class User(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    val id: Long = 0L,
    @ColumnInfo(name = "name")
    val name: String = "",
    @Column(name = "height")
    val height: Long = 0L
)

@Database(
    entities = [User::class],
    version = 2
)
abstract class UserDB : RoomDatabase() {
    object ManualMigrations {
        val M_1_2 = object : Migration(1, 2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL("ALTER TABLE user ADD COLUMN height INTEGER NOT NULL DEFAULT 0")
            }
        }
    }
}

Now I want to deprecate all manual migration and use auto-migration instead. I change the code and got an error:

// Compile Time Error: 
// New NOT NULL column'height' added with no default value specified. 
// Please specify the default value using @ColumnInfo.
@Database(
    entities = [User::class],
    autoMigrations = [
        AutoMigration(from = 1, to = 2)
    ],
    version = 2
)
abstract class UserDB : RoomDatabase()

even if I have specify default value by @ColumnInfo, but still got same error:

// Compile Time Error: 
// New NOT NULL column'height' added with no default value specified. 
// Please specify the default value using @ColumnInfo.
@Entity(tableName = "user")
data class User(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    val id: Long = 0L,
    @ColumnInfo(name = "name")
    val name: String = "",
    // specify default value by this way
    @Column(name = "height", defaultValue = "0")
    val height: Long = 0L
)

@Database(
    entities = [User::class],
    autoMigrations = [
        AutoMigration(from = 1, to = 3)
    ],
    // Since I have modify the structure of table, 
    // I increase the version.
    version = 3
)
abstract class UserDB : RoomDatabase()

What wrong with my code and how can i fix this error?

Update

I have modify the annotation of height field

from

@Column(name = "height", defaultValue = "0")
val height: Long = 0L

to

@ColumnInfo(name = "height", defaultValue = "0")
val height: Long = 0L

And follow above step but get a runtime exception

  1. fully uninstall app, and install the app with database version = 1;
  2. add new column height with annotation: @ColumnInfo(name = "height") and database version update to version 2 by writing manual migration. then run new version app;
  3. to use auto-migration, I delete manual migration and update height field annotation: @ColumnInfo(name = "height", defaultValue = "0") (if I not specify default value, room compiler will tell me I must specify default value by throwing Exception during compile time) and increase version from 2 to 3, and specify autoMigrations into @Database:
@Database(
    entities = [Worker::class],
    autoMigrations = [AutoMigration(from = 1, to = 3)],
    version = 3
)
abstract class UserDB : RoomDatabase()

Then at runtime execute these code and got an runtime exception:

val userDB = buildUserDB().openHelper.readableDatabase
            Log.d(TAG, "columnNames=${workerDB.query("SELECT * FROM user").columnNames.toList()}")

// java.lang.IllegalStateException: A migration from 2 to 3 was required but not found. 
// Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...) 
// or allow for destructive migrations via one of the 
// RoomDatabase.Builder.fallbackToDestructiveMigration* methods.
like image 805
ZSpirytus Avatar asked Nov 02 '25 11:11

ZSpirytus


1 Answers

even if I have specify default value by @ColumnInfo, but still got same error:

I believe (according to the long version) that your issue is that you are using @Column(.... instead of @ColumnInfo(.....

So change

@Column(name = "height", defaultValue = "0")
val height: Long = 0L

to

@ColumnInfo(name = "height", defaultValue = "0")
val height: Long = 0L

Testing the above using two runs one at version 1 and then 2 (using corrected @ColumnInfo) using:-

class MainActivity : AppCompatActivity() {
    lateinit var db: UserDB
    lateinit var dao: UserDao
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        db = UserDB.getInstance(this)
        dao = db.getUserDao()

        dao.insert(User(name = "NAME001Version$DATABASE_VERSION"))
        dao.insert(User(name = "NAME002Version$DATABASE_VERSION"))
        dao.insert(User(name = "NAME003Version$DATABASE_VERSION"))

        for (u in dao.getAllUsers()) {
            Log.d("DBINFO","User ID = ${u.id} UserName is ${u.name} Version is ${DATABASE_VERSION}")
        }
    }
}
  • Where DATABASE_VERSION is the version #

The DB via App inspection is :-

enter image description here

The logs from both runs :-

2022-05-24 19:32:57.784 D/DBINFO: User ID = 1 UserName is NAME001Version1 Version is 1
2022-05-24 19:32:57.784 D/DBINFO: User ID = 2 UserName is NAME002Version1 Version is 1
2022-05-24 19:32:57.784 D/DBINFO: User ID = 3 UserName is NAME003Version1 Version is 1



2022-05-24 19:38:41.963 D/DBINFO: User ID = 1 UserName is NAME001Version1 Version is 2
2022-05-24 19:38:41.963 D/DBINFO: User ID = 2 UserName is NAME002Version1 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 3 UserName is NAME003Version1 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 4 UserName is NAME001Version2 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 5 UserName is NAME002Version2 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 6 UserName is NAME003Version2 Version is 2

To replicate the issue (had to add a basic annotation for @Column) and then:-

enter image description here

like image 169
MikeT Avatar answered Nov 04 '25 00:11

MikeT



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!