You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Room数据库迁移添加列失败,表结构匹配异常排查

问题描述

我定义了如下UserEntity数据类:

data class UserEntity(
@PrimaryKey var uid: String,
var name: String?,
var photo: String?,
var status: Int = 0,
var interaction: Long? = null,
var additional: String? = ""
)

编写了从版本1到2的数据库迁移逻辑:

private val MIGRATION_1_2 = object : Migration(1, 2) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("ALTER TABLE UserEntity ADD COLUMN additional TEXT NOT NULL DEFAULT ''")
        }
    }

运行时抛出以下异常:

Caused by: java.lang.IllegalStateException: Migration didn't properly handle: UserEntity(com.michlindevelopment.way.mainapp.database.UserEntity).
                                                                                                 Expected:
                                                                                                TableInfo{name='UserEntity', columns={name=Column{name='name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}, interaction=Column{name='interaction', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}, uid=Column{name='uid', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}, photo=Column{name='photo', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}, status=Column{name='status', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, additional=Column{name='additional', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}}, foreignKeys=[], indices=[]}
                                                                                                 Found:
                                                                                                TableInfo{name='UserEntity', columns={uid=Column{name='uid', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='undefined'}, name=Column{name='name', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}, photo=Column{name='photo', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}, status=Column{name='status', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, interaction=Column{name='interaction', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}, additional=Column{name='additional', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}}, foreignKeys=[], indices=[]}

我怀疑是列顺序问题?预期中name列排在首位,但实际查询到uid列排在首位。

解决方案

列顺序不是问题,Room在校验表结构时不会在意列的排列顺序。真正的冲突点在additional列的约束上:

  • 数据类中additional是String?(可空类型),所以Room预期该列是notNull=false,默认值无约束(显示为undefined)
  • 但你的迁移语句里给该列加了NOT NULL约束,还设置了默认值'',导致实际表结构中该列是notNull=true,和预期不匹配

有两种修复方式:

方式一:修改迁移语句,匹配数据类的可空设置

去掉NOT NULL约束,让列变为可空:

private val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE UserEntity ADD COLUMN additional TEXT DEFAULT ''")
    }
}

方式二:修改数据类,匹配迁移语句的非空设置

把additional改为非空类型,去掉问号:

data class UserEntity(
@PrimaryKey var uid: String,
var name: String?,
var photo: String?,
var status: Int = 0,
var interaction: Long? = null,
var additional: String = "" // 改为非空类型
)

根据你的业务需求选择即可:如果业务允许additional为空,选方式一;如果要求该字段必须有值,选方式二。

内容的提问来源于stack exchange,提问作者Dim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 10:57:19