在复杂的架构更改中,会议室迁移失败

时间:2019-01-28 14:22:08

标签: android kotlin android-sqlite android-room

我正在尝试更新会议室数据库 想要在现有数据库中添加两列,并且不想丢失数据。

我现有的表名WordTable

@Entity
data class WordTable(
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
    var word: String = "",
    var des: String = "",
    var bookmark: Boolean = false,
    var addByUser: Boolean = false,
    var uploaded: Boolean = false)

我想添加这两列,所以我的代码现在是

@Entity
data class WordTable(
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,
    var word: String = "",
    var des: String = "",
    var ref: String = "Added by user",
    var recent: Date = Date(),
    var bookmark: Boolean = false,
    var addByUser: Boolean = false,
    var uploaded: Boolean = false)

注意:我提供日期换算器

创建一个新表

database.execSQL("CREATE TABLE users (id INTEGER PRIMARY KEY AUTOINCREMENT," +
                    " word TEXT," +
                    " des TEXT," +
                    " ref TEXT," +
                    " recent INTEGER," +
                    " bookmark INTEGER," +
                    " addByUser INTEGER," +
                    " uploaded INTEGER)")

复制以前的数据

database.execSQL("Insert Into USER (id, word, des, bookmark, addByUser, uploaded) Select * From WordTable")

删除单词表

database.execSQL("Drop Table WordTable")

将用户表重命名为WordTable

database.execSQL("Alter Table USER RENAME TO WordTable")

我得到这个错误;

Expected:
TableInfo{name='WordTable', columns={addByUser=Column{name='addByUser', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, word=Column{name='word', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, bookmark=Column{name='bookmark', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, uploaded=Column{name='uploaded', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1}, ref=Column{name='ref', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, des=Column{name='des', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0}, recent=Column{name='recent', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='WordTable', columns={addByUser=Column{name='addByUser', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0}, word=Column{name='word', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, bookmark=Column{name='bookmark', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0}, uploaded=Column{name='uploaded', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1}, ref=Column{name='ref', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, des=Column{name='des', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0}, recent=Column{name='recent', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0}}, foreignKeys=[], indices=[]}

预期与发现之间的差异是

Expected: notNull=true
Found: notNull=false

所以我尝试修改创建表代码

database.execSQL("CREATE TABLE `USER` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `word` TEXT NOT NULL, `des` TEXT NOT NULL, `ref` TEXT NOT NULL, `recent` INTEGER NOT NULL, `bookmark` INTEGER NOT NULL, `addByUser` INTEGER NOT NULL, `uploaded` INTEGER NOT NULL)")

但是这次我得到这个错误:

android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: USER.ref (Sqlite code 1299), (OS error - 2:No such file or directory)
at android.database.sqlite.SQLiteConnection.nativeExecuteForChangedRowCount(Native Method)
at android.database.sqlite.SQLiteConnection.executeForChangedRowCount(SQLiteConnection.java:742)

我也尝试更改表和列,但得到相同的错误。

我该如何解决?

4 个答案:

答案 0 :(得分:0)

您可以复制查询以创建表或从生成的会议室数据库文件中修改表。

只需双击并查找_Impl。

您的问题与表中的NON NULL数据类型有关,您需要将这些字段指定为NON NULL并处理在房间迁移期间需要分配的DEFAULT值。

答案 1 :(得分:0)

您不需要建立新表 创建类似的方法:

  private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
            @Override
            public void migrate(@NonNull SupportSQLiteDatabase database) {
                   database.execSQL("ALTER TABLE `WordTable` ADD COLUMN ref STRING");
            }
        };

并调用数据库创建方法,例如:

Room.databaseBuilder(/*parameter want */).addMigrations(MIGRATION_1_2).allowMainThreadQueries().build();

答案 2 :(得分:0)

您可以使用ALTER TABLE查询并仅提供迁移

private static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("ALTER TABLE `table_name` ADD COLUMN `column_name` {type} DEFAULT {defaultValue} NOT NULL");
        }
    };

当您尝试更改表时,应为表中已经存在的所有其他记录提供默认值。

答案 3 :(得分:0)

错误消息中的Expected和Found之间的区别是表中的非null约束。

如果希望这些行可为空,则将它们的变量定义为没有默认值的对象,并构造一个定义所需行的构造函数。实例化变量时不要同时实例化行值!

如果您希望行从不接受Null,请在SQLite查询的行末尾添加NOT NULL,而不必更改模型类。