Android Room迁移问题:基本类型NonNull导致user_groups表不匹配
解决Room迁移时
user_groups表is_default列NOT NULL约束不匹配问题 这个问题我之前帮别人排查过,核心原因是Room对Java基本类型的默认映射规则:你在Entity里用了int isDefault基本类型,Room会自动把对应的列标记为NOT NULL,但旧表的is_default列没有这个约束,导致迁移校验失败。下面给你两种可行的解决方案,按工作量从少到多排序:
方案一:修改Entity字段类型(零数据库改动,推荐)
最简单的绕过方式是把int基本类型改成Integer包装类型,这样Room就不会强制要求列必须NOT NULL,完美匹配旧表的结构:
修改后的Entity代码:
@Entity(tableName = "user_groups") public class UserGroupModel { @PrimaryKey @NonNull @ColumnInfo(name = "_id") private String rowId; @ColumnInfo(name = "is_default") private Integer isDefault; // 从int改成Integer // 对应的构造器、getter/setter也要同步修改为Integer类型 public UserGroupModel(@NonNull String rowId, Integer isDefault) { this.rowId = rowId; this.isDefault = isDefault; } public Integer getIsDefault() { return isDefault; } // 业务逻辑里可以处理null的情况,比如默认返回0(对应原表的DEFAULT 0) public int getIsDefaultOrDefault() { return isDefault != null ? isDefault : 0; } }
这种方法不需要修改任何现有数据库,只改Entity代码就能通过Room的迁移校验,工作量最小。
方案二:通过迁移脚本修改表结构(需要修改现有数据)
如果你因为业务需求必须保持int基本类型,那确实需要把旧表的is_default列改成NOT NULL。注意SQLite不支持直接修改列的约束,需要通过临时表迁移数据的方式实现,具体迁移脚本如下:
在你的Migration类中添加以下SQL逻辑:
static final Migration MIGRATION_X_TO_Y = new Migration(X, Y) { @Override public void migrate(@NonNull SupportSQLiteDatabase database) { // 1. 创建临时表,包含NOT NULL约束和默认值 database.execSQL("CREATE TABLE user_groups_temp (_id TEXT PRIMARY KEY, is_default INTEGER NOT NULL DEFAULT 0)"); // 2. 迁移数据,把null的is_default替换为0(符合原表的默认值设置) database.execSQL("INSERT INTO user_groups_temp (_id, is_default) SELECT _id, COALESCE(is_default, 0) FROM user_groups"); // 3. 删除原表 database.execSQL("DROP TABLE user_groups"); // 4. 重命名临时表为原表名 database.execSQL("ALTER TABLE user_groups_temp RENAME TO user_groups"); } };
这个脚本会自动处理现有数据中的null值,把它们转为默认的0,同时给列加上NOT NULL约束,之后Room的校验就能通过。
内容的提问来源于stack exchange,提问作者Le2e410
相关产品推荐
相关产品推荐

