Skip to content
Advertisement

How to set a default value to existing rows for a new column created using Room Auto-Migrations?

I have a Room SQL table with several columns. And I want to add one more column to it containing a boolean value. For migrating my database to this new schema, I am trying to use Room Auto-Migrations. My question is how can I update my existing rows in the table to have a value false for this newly added column? Will I have to fallback to writing manual migration by altering the table and inserting the default value to all rows?

Advertisement

Answer

My question is how can I update my existing rows in the table to have a value false for this newly added column?

Use the @ColumnInfo‘s defalutValue e.g. for the column in the Entity.

@ColumnInfo(defaultValue = "0") 

Will I have to fallback to writing manual migration by altering the table and inserting the default value to all rows?

This should then add column with the default value clause when Auto Migrating.

  • I believe (if memory serves) that if you do not code a default value then the auto migration would fail due to the absence of a default value for the new column.

Additional

If you then wanted to Insert using the default value you would not be able to use the convenience @Insert annotation in the respective interface/asbstract class that is annotated with @Dao but would have to use an @Query that list the columns omitting the columns that are to use the default, and that has the VALUES clause specifying the values of the named columns.

e.g. for a table with 3 columns, columna, columnb and columnc; where columnc has a DEFAULT specified then the insert function could be something like:-

@Query("INSERT INTO the_table (columna,columnb) VALUES(:valueForColumnA,:valueForColumnB);")
fun insertWithDefaultValueForColumnC(valueForColumnA: TheType,valueForColumnB: TheType): Long
  • note the above is in-principle code, it has not been compiled, tested or run so may contain some errors.

Additional re comment

I tried @ColumnInfo(defaultValue = “1”) and @ColumnInfo(defaultValue = “true”) to set the default value to true. But that didn’t work.

defaultValue = "1" or defaultvalue = "0" do work (1 is true 0 is false).

However, default = "false" or default = "true" DO NOT work as expected. They would have similar results to default = "whatever....".

Perhaps a bug, perhaps an issue with Room. What happens with the latter is that they are passed as String (TEXT in SQLite) and thus are actually inserted as such even though the column has been defined as Boolean. Such values are allowed by SQLite dues to the flexibility that any column can store any type.

Consider the following Entity:-

@Entity
data class Example1(
    @PrimaryKey
    val id: Long? = null,
    val name: String,
    /*
     ADDITIONS FOR V2
     */
    @ColumnInfo(defaultValue = "1")
    val b1: Boolean,
    @ColumnInfo(defaultValue = "0")
    val b2: Boolean,
    @ColumnInfo(defaultValue = "false")
    val b3: Boolean,
    @ColumnInfo(defaultValue = "true")
    val b4: Boolean
)
  • Where b1-b4 are added and an Automigration done when 10 rows existed when Version 1 was run and another 10 are run when Version 2 is run and another 10 columns are added as per :-

      db = TheDatabase.getInstance(this)
      dao = db.getAllDao()
      for (i in 1..10) {
          dao.insert(Example1(name = "V${DATABASE_VERSION}_$i", b1 = true, b2 = true, b3 = true, b4 = true))
      }
    
      for(e: Example1 in dao.getAllExample1s()) {
          Log.d("DBINFO","Name is ${e.name} id id ${e.id} " +
          /*" ADDED COL = There Aren't any" */
          " B1=${e.b1} B2=${e.b2} B3=${e.b3} B4=${e.b4}"
          )
      }
    

The result of the 2nd run is :-

2022-01-05 09:41:43.503 D/DBINFO: Name is V1_1 id id 1  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_2 id id 2  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_3 id id 3  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_4 id id 4  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_5 id id 5  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_6 id id 6  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_7 id id 7  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_8 id id 8  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_9 id id 9  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V1_10 id id 10  B1=true B2=false B3=false B4=false
2022-01-05 09:41:43.504 D/DBINFO: Name is V2_1 id id 11  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.504 D/DBINFO: Name is V2_2 id id 12  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.505 D/DBINFO: Name is V2_3 id id 13  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.505 D/DBINFO: Name is V2_4 id id 14  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.505 D/DBINFO: Name is V2_5 id id 15  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.505 D/DBINFO: Name is V2_6 id id 16  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.505 D/DBINFO: Name is V2_7 id id 17  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.505 D/DBINFO: Name is V2_8 id id 18  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.506 D/DBINFO: Name is V2_9 id id 19  B1=true B2=true B3=true B4=true
2022-01-05 09:41:43.506 D/DBINFO: Name is V2_10 id id 20  B1=true B2=true B3=true B4=true

The first 10 rows have had the default value applied as per:-

  • b1 is true as per the coded default value i.e. 1 = true
  • b2 is false as per the coded default value i.e. 0 = false
  • b3 and b4 are false because the value is the TEXT/STRING (as will be shown) which cannot be converted to an Int and therefore rather than an exception occurring it is converted to 0 and thus false.

If App Inspection is used to view the data it shows :-

enter image description here

If again using App Inspection/Database Inspector and the table queried using SELECT *,typeof(b1),typeof(b2),typeof(b3),typeof(b4) FROM example1; then :-

enter image description here

i.e. columns b3 and b4 for the 10 rows that existed prior to the AutoMigration are saved as TEXT.

User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement