首页 > 解决方案 > 房间迁移 - 将 INTEGER 列类型更改为可为空 (SQLLITE)

问题描述

我有一个带有 int 列的版本 1 数据库。在版本 2 中,我想让我的列可以为空,为此我在我的 java 实体类中将列数据类型从 int 更改为 Integer。

因为经过一些研究,我意识到不可能只更改列的数据类型。

这是我在迁移方法中所做的:

我的原始实体名称是TaskEntity,我正在创建一个新的临时表,复制数据然后删除原始表,然后将临时表重命名为原始表。

        database.execSQL(
                "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));" +

                "INSERT INTO TaskEntityNew(text,caseid,status,datetime,updateDt) SELECT text,caseid,status,datetime,update FROM TaskEntity;"+

                "DROP TABLE TaskEntity;" +

                "ALTER TABLE 'TaskEntityNew' RENAME TO 'TaskEntity';" +

                "COMMIT;"
        );

但我收到了这个错误

 Caused by: java.lang.IllegalStateException: Migration didn't properly handle TaskEntity(EntityCollection.TaskEntity).
                                                                                 Expected:
                                                                                TableInfo{name='TaskEntity', columns={text=Column{name='text', type='TEXT', notNull=false, primaryKeyPosition=0}, updateDt=Column{name='updateDt', type='INTEGER', notNull=false, primaryKeyPosition=0}, datetime=Column{name='datetime', type='INTEGER', notNull=false, primaryKeyPosition=0}, status=Column{name='status', type='INTEGER', notNull=true, primaryKeyPosition=0}, caseid=Column{name='caseid', type='INTEGER', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=[ForeignKey{referenceTable='CaseEntity', onDelete='CASCADE', onUpdate='NO ACTION', columnNames=[caseid], referenceColumnNames=[id]}], indices=[Index{name='index_TaskEntity_caseid', unique=false, columns=[caseid]}]}
                                                                                 Found:
                                                                                TableInfo{name='TaskEntity', columns={text=Column{name='text', type='TEXT', notNull=false, primaryKeyPosition=0}, updateDt=Column{name='updateDt', type='INTEGER', notNull=false, primaryKeyPosition=0}, datetime=Column{name='datetime', type='INTEGER', notNull=false, primaryKeyPosition=0}, status=Column{name='status', type='INTEGER', notNull=true, primaryKeyPosition=0}, caseid=Column{name='caseid', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=[ForeignKey{referenceTable='CaseEntity', onDelete='CASCADE', onUpdate='NO ACTION', columnNames=[caseid], referenceColumnNames=[id]}], indices=[Index{name='index_TaskEntity_caseid', unique=false, columns=[caseid]}]}

我能想到的一个问题是我的 SQL 块没有执行,而我的旧表数据正试图与旧的 java 实体类匹配。任何帮助将不胜感激!

标签: androidsqliteandroid-room

解决方案


根据文档,execSQL只执行一条 SQL 语句:

要执行的 SQL 语句。不支持以分号分隔的多个语句。

因此您需要将代码重写为多个调用,例如:

database.execSQL("BEGIN TRANSACTION;");

database.execSQL("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));");

database.execSQL("INSERT INTO TaskEntityNew(text,caseid,status,datetime,updateDt) SELECT text,caseid,status,datetime,update FROM TaskEntity;");

database.execSQL("DROP TABLE TaskEntity;");

database.execSQL("ALTER TABLE 'TaskEntityNew' RENAME TO 'TaskEntity';");

database.execSQL("COMMIT;");

按原样,SQLite 正在执行“BEGIN TRANSACTION;” 然后忽略其余的 SQL 语句。


推荐阅读