房间迁移 - "notNull" 属性 显示错误信息

Room Migration - "notNull" property shows wrong information

最近,我决定将我的应用程序从 Java 重写为 Kotlin。 问题是房间 returns 中的迁移是一个奇怪的异常。

这是我的部分数据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
)

以及异常本身:

注意:我没有自己更改列,所以我的迁移看起来像这样:

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

谁能告诉我为什么我看到的是 notNull=true 而不是 notNull=false

提前致谢!

a weird exception

不是真的。 Room 期望能够 build/use/map 对象与数据库中的内容。因此,它会检查现有数据库是否符合预期。如果没有,那么它会报告它所期望的和它发现的。

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

通过指定 ?(例如 var myRating: Float? = null),Room 会将其解释为可以为 null,因此 NOT NULL = false。您在 FOUND 中看到 true 的原因是,这是要迁移的现有数据库架构中的内容。

当您从 java 转换为 null 时,您必须意识到 Kotlin Int 等同于 Java Ineteger 对象而不是 java int.

Java 具有 int、long、boolean 等原语 ..... 不能为 null 它们总是有一个值,因此将被 Room 标记为 NOT NULL,因为它们不可为 null。

Kotlin 没有基元只有对象所以 Kotlin Int 等同于 java Integer。对象可以为空,因此 Room 允许它们为空。

解决问题 因此,您可以选择

  • a) 将实体更改为不使用?或
  • b) 更改 table 以便不对 NOT NULL 进行编码。但是,您仅限于只能重命名列,不能(直接)更改任何其他属性。

如果选择 b) 那么我建议,因为你不是 adding/removing 列,在迁移中使用 :-

  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.
  • 注意以上为原理代码,未经过compiled/tested或运行,因此可能包含一些错误。