Android Room迁移时非空字段被期望默认值为null如何解决
问题原因
这是Room的表结构校验规则和你写的迁移逻辑不匹配导致的,核心逻辑如下:
- Kotlin实体类构造参数的默认值
= 0是代码层面的默认值,仅在你代码中初始化实体类对象时生效,不会自动同步为SQL表的列默认值。 - Room只有当你给字段加上
@ColumnInfo(defaultValue = "...")注解时,才会认为该字段需要配置SQL级别的默认值。你当前没有加这个注解,所以Room预期这两个字段的SQL默认值为null。 - 你写的迁移语句中给两个字段都加了
DEFAULT 0的SQL默认值,导致实际表结构的默认值为0,和Room预期的null不一致,因此触发迁移校验失败。
解决方法
你可以根据实际需求选其中一种方案处理:
方案1:保留SQL级别的默认值(推荐,旧数据会自动填充0)
给实体类的两个字段加上@ColumnInfo注解声明默认值即可:
@Entity( tableName = "invoices", indices = [Index(value = [...], unique = true)] ) data class Invoice( ... @ColumnInfo(defaultValue = "0") override val created_at: Long = 0, @ColumnInfo(defaultValue = "0") override var approved_at: Long? = 0, ) : ICD
方案2:移除SQL级别的默认值,仅保留代码层面的默认值
修改迁移语句,去掉DEFAULT子句,注意非空字段需要先给已有旧数据补值:
val MIGRATION_3_4 = object: Migration(3, 4) { override fun migrate(database: SupportSQLiteDatabase) { // 非空字段先加允许空、补全旧数据、再修改为非空 database.execSQL("ALTER TABLE invoices ADD COLUMN created_at INTEGER") database.execSQL("UPDATE invoices SET created_at = 0") database.execSQL("ALTER TABLE invoices ALTER COLUMN created_at INTEGER NOT NULL") // 可空字段直接新增即可 database.execSQL("ALTER TABLE invoices ADD COLUMN approved_at INTEGER") } }
注:如果你的项目依赖的SQLite版本不支持
ALTER COLUMN语法,可以用Room官方推荐的「创建临时表→迁移数据→删除旧表→重命名临时表」的流程完成字段修改。
内容的提问来源于stack exchange,提问作者AmSabba
相关产品推荐
相关产品推荐

