Home > Software design >  Room Migration - "notNull" property shows wrong information
Room Migration - "notNull" property shows wrong information

Time:12-27

Recently, I decided to rewrite my app from Java to Kotlin. The issue is that migration in Room returns a weird exception.

Here is part of my data class

@Entity(tableName = Constants.MOVIE_TABLE)
data class Movie(
    @ColumnInfo(name = "adult") var adult: Boolean? = null,
    @Ignore @ColumnInfo(name = "backdrop_path") var backdropPath: String? = null,
    @ColumnInfo(name = "budget") var budget: Long? = null,
    @Ignore var genres: List<MovieGenre>? = emptyList(),
    @Ignore var homepage: String? = null,
    @PrimaryKey @ColumnInfo(name = "id") var id: Int? = null,
    ...
    @ColumnInfo(name = "vote_average")var voteAverage: Double? = null,
    @ColumnInfo(name = "vote_count") var voteCount: Int? = null,
    @ColumnInfo(name = "added_date") var addedDate: Date? = null,
    @ColumnInfo(name = "my_rating") var myRating: Float? = null
)

And the exception itself: Expected, Found

NOTE: I did not change the columns themself, so my migration looks like this:

internal val WATCHED_MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
 
    }
}

Can someone tells me why I see notNull=true instead of notNull=false?

Thanks in advance!

CodePudding user response:

a weird exception

Not really. Room has expectations so as to be able to build/use/map objects with what is in the database. As such it checks that the existing database is as per it's expectations. If not then it reports on what it expects and what it found.

Can someone tells me why I see notNull=true instead of notNull=false?

By specifying ? (e.g. var myRating: Float? = null) then Room interprets it as being able to be null so NOT NULL = false. The reason why you see true in the FOUND is that this is what is in the schema of the database that exists that is to be migrated.

As you are converting from java to null then you have to realise that Kotlin Int is equivalent to Java Ineteger object not java int.

Java has primitives such as int, long, boolean ..... which cannot be null they always have a value and thus will be marked as NOT NULL by Room as they are not nullable.

Kotlin does not have primitives only Objects so Kotlin Int is equivalent to java Integer. Objects can be null so Room allows them to be null.

Fixing the Issue(s) As such you have the option to

  • a) change the Entity to not use ? or
  • b) to ALTER the table so that NOT NULL is not encoded. However you are limited to only being able to RENAME a column, you cannot (directly) change any of the other attributes.

If taking option b) then I would suggest, as you are not adding/removing columns, is in the migration use :-

  1. database.execSQL("DROP TABLE IF EXISTS " Constants.MOVIE_TABLE "_old;")
  2. database.execSQL("ALTER TABLE " Constants.MOVIE_TABLE " RENAME TO " Constants.MOVIE_TABLE "_old;"
  3. database.exeSQL("THE CREATE TABLE STATEMENT COPIED FROM THE GENERATED JAVA SEE NOTE")
  4. database.exeSQL("INSERT INTO " Constants.MOVIE_TABLE " SELECT * FROM " Constants.MOVIE_TABLE "_old;")
  5. database.execSQL("DROP TABLE IF EXISTS " Constants.MOVIE_TABLE "_old;")
  6. database.execSQL("VACUUM;")

Note

  • The generated java can be found by using the Android View in android studio.
  • There will be a class that will have the same name as the class that is annotated with @Database but suffixed with _Impl. Within the class there will be a method/function entitled createAlltables this will include a line for the creation of all tables that will include the SQL that EXACTLY matches what Room expects. Use this to replace THE CREATE TABLE STATEMENT COPIED FROM THE GENERATED JAVA SEE NOTE above.
  • Note the above is in-principle code, it has not been compiled/tested or run and may therefore contain some error.
  • Related