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

Android Room数据库:添加NOT NULL列报错及列类型修改迁移方法

问题分析与解决方案

异常原因

SQLite 不允许直接给已有数据的表添加 NOT NULL 约束且未指定默认值的列——因为现有行的新列会被自动赋值为 NULL,这直接违反了 NOT NULL 约束,从而触发 SQLiteException。


解决方案一:添加带默认值的非空列

如果业务需要这两列必须为非空,修改迁移代码时给新列指定默认值(比如空字符串),确保现有行的新列值符合约束要求:

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        // 添加带默认空字符串的非空列
        database.execSQL("ALTER TABLE LearningMaterialChildDetailEntity ADD COLUMN classes TEXT NOT NULL DEFAULT ''");
        database.execSQL("ALTER TABLE LearningMaterialChildDetailEntity ADD COLUMN school TEXT NOT NULL DEFAULT ''");
    }
};

同时同步修改对应的 Entity 实体类,确保字段定义与数据库约束一致:

@Entity(tableName = "LearningMaterialChildDetailEntity")
public class LearningMaterialChildDetailEntity {
    // 其他已有字段...
    
    @ColumnInfo(name = "classes", nullable = false)
    private String classes;

    @ColumnInfo(name = "school", nullable = false)
    private String school;
    
    // Getter、Setter 方法...
}

解决方案二:添加允许为空的 TEXT 列

如果业务允许这两列的值为空,直接去掉 NOT NULL 约束即可:

static final Migration MIGRATION_2_3 = new Migration(2, 3) {
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        database.execSQL("ALTER TABLE LearningMaterialChildDetailEntity ADD COLUMN classes TEXT");
        database.execSQL("ALTER TABLE LearningMaterialChildDetailEntity ADD COLUMN school TEXT");
    }
};

实体类中对应字段可省略 nullable = false(默认即为允许为空):

@Entity(tableName = "LearningMaterialChildDetailEntity")
public class LearningMaterialChildDetailEntity {
    // 其他已有字段...
    
    @ColumnInfo(name = "classes")
    private String classes;

    @ColumnInfo(name = "school")
    private String school;
    
    // Getter、Setter 方法...
}

如何将已有的 TEXT NOT NULL 列改为 TEXT(允许为空)

SQLite 不支持直接通过 ALTER TABLE 修改列的约束,需通过临时表中转实现:

static final Migration MIGRATION_3_4 = new Migration(3, 4) { // 版本号对应实际升级版本
    @Override
    public void migrate(SupportSQLiteDatabase database) {
        // 1. 创建临时表,复制原表结构但去掉目标列的 NOT NULL 约束
        database.execSQL("CREATE TABLE temp_LearningMaterialChildDetailEntity (" +
                "id INTEGER PRIMARY KEY AUTOINCREMENT," + // 替换为原表实际主键
                "other_column1 TEXT," + // 替换为原表其他所有字段
                "classes TEXT," + // 去掉 NOT NULL 约束
                "school TEXT" + // 去掉 NOT NULL 约束
                ")");

        // 2. 将原表数据导入临时表
        database.execSQL("INSERT INTO temp_LearningMaterialChildDetailEntity SELECT * FROM LearningMaterialChildDetailEntity");

        // 3. 删除原表
        database.execSQL("DROP TABLE LearningMaterialChildDetailEntity");

        // 4. 将临时表重命名为原表名
        database.execSQL("ALTER TABLE temp_LearningMaterialChildDetailEntity RENAME TO LearningMaterialChildDetailEntity");
    }
};

注意:需严格复制原表的所有字段、主键、索引等结构(仅修改目标列的约束),避免数据丢失或结构异常;同时同步修改实体类中对应字段的 nullable 属性为 true。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 11:12:23