Room迁移问题:SQLite中将INTEGER列改为可空类型
解决Room迁移中列可空性修改失败的问题
从你给出的错误日志里能一眼看到核心问题:Expected的caseid列是notNull=false(可空),但Found里它还是notNull=true(非空),这说明你的迁移SQL根本没执行成功,旧表的结构完全没变化,所以Room才会抛出结构不匹配的异常。
问题根源:你的SQL有语法错误
仔细看你写的CREATE TABLE语句片段:
"'datetime' DATETIME," + ",'updateDt' DATETIME,"
这里datetime列的结尾多了一个多余的逗号,导致整个SQL语句语法错误,数据库执行时直接回滚了整个事务,旧表自然没被替换,结构还是原来的非空状态。
修正后的完整迁移SQL
我帮你修正了语法错误,同时补全了和实体类匹配的外键约束、索引,确保结构完全对齐:
BEGIN TRANSACTION; -- 创建和目标结构一致的临时表 CREATE TABLE TaskEntityNew( 'id' INTEGER PRIMARY KEY AUTOINCREMENT, 'text' TEXT, 'caseid' INTEGER NULL, 'status' INTEGER NOT NULL DEFAULT 0, 'datetime' DATETIME, 'updateDt' DATETIME, FOREIGN KEY (caseid) REFERENCES CaseEntity(id) ON DELETE CASCADE ); -- 复制原表数据(注意列名要和原表完全对应,这里假设原表的更新时间列是updateDt,不是update) INSERT INTO TaskEntityNew(text,caseid,status,datetime,updateDt) SELECT text,caseid,status,datetime,updateDt FROM TaskEntity; -- 替换原表 DROP TABLE TaskEntity; ALTER TABLE 'TaskEntityNew' RENAME TO 'TaskEntity'; -- 重建实体类定义的索引 CREATE INDEX index_TaskEntity_caseid ON TaskEntity(caseid); COMMIT;
额外注意点
- 列名一致性:你的原INSERT语句里写的是
SELECT ... update FROM TaskEntity,但新表列名是updateDt,如果原表的列名是updateDt,一定要改成updateDt,否则会导致数据复制失败。 - 外键约束匹配:错误日志里显示原外键带有
ON DELETE CASCADE属性,你的原SQL里没加这个约束,必须补上才能让Room认为结构一致。 - 索引重建:临时表不会自动继承原表的索引,所以需要手动创建实体类定义的
index_TaskEntity_caseid索引。
把修正后的SQL替换到你的迁移方法里,再测试迁移就能解决这个问题了。
内容的提问来源于stack exchange,提问作者aashish
相关产品推荐
相关产品推荐

