Room Database Migration doesnt properly handle ALTER TABLE migration

后端 未结 7 2003
渐次进展
渐次进展 2020-12-13 06:36

Java.lang.IllegalStateException

Migration didn\'t properly handle user(therealandroid.github.com.roomcore.java.User).

Expected:

TableInfo{n

相关标签:
7条回答
  • 2020-12-13 06:45

    I have faced notNull differences in kotlin and found exception like below

    Expected:
    TableInfo{name='enDic', columns={definition=Column{name='definition', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, _id=Column{name='_id', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, favourite=Column{name='favourite', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, word=Column{name='word', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, usage=Column{name='usage', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
    Found:
    TableInfo{name='enDic', columns={usage=Column{name='usage', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, definition=Column{name='definition', type='text', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, _id=Column{name='_id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, favourite=Column{name='favourite', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, word=Column{name='word', type='text', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
    

    Then I used below mentioned code to solve that problem

    @Entity(tableName = "enDic")
    data class Word(
    
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "_id")
        var _id: Int?,
    
        @ColumnInfo(name = "word")
        var word: String?,
    
        @ColumnInfo(name = "definition")
        var definition: String,
    
        @ColumnInfo(name = "favourite")
        var favourite: Int?,
    
        @ColumnInfo(name = "usage")
        var usage: Int?
    
    )
    

    Instead of this code

    @Entity(tableName = "enDic")
    data class Word(
    
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "_id")
        var _id: Int,
    
        @ColumnInfo(name = "word")
        var word: String,
    
        @ColumnInfo(name = "definition")
        var definition: String,
    
        @ColumnInfo(name = "favourite")
        var favourite: Int,
    
        @ColumnInfo(name = "usage")
        var usage: Int
    
    )
    
    0 讨论(0)
  • 2020-12-13 06:47

    if you want to add Integer type column , add this code

    database.execSQL("ALTER TABLE users"
                        + " ADD COLUMN year INTEGER NOT NULL DEFAULT 0 ")
    
    0 讨论(0)
  • 2020-12-13 06:48

    I faced this issue today, I just changed int fields to Integer in Entities. As int cannot be null but Integer objects could be null.

    0 讨论(0)
  • 2020-12-13 06:50

    If you are getting notNull differences, you can simply mark your class field with @NonNull annotation, or change your sql with ALTER TABLE. But if you are getting column type differences, such as expected: TYPE=TEXT, then found TYPE='' (COLLATE NOCASE), or expected INTEGER, found INT, then the only solution is to drop and recreate your table. Sqlite does not allow changing column types.

    Use INTEGER in Sqlite instead of INT and mark your Java entity with @ColumnInfo(collate = NOCASE) (if you use NOCASE in Sqlite).

    Take a look at the json file under app\schemas to get the sql for the expected queries.

    static final Migration MIGRATION_2_3= new Migration(2, 3) {
            @Override
            public void migrate(SupportSQLiteDatabase database) {
    
                database.execSQL("DROP TABLE IF EXISTS table_tmp");
    
                database.execSQL("CREATE TABLE IF NOT EXISTS `table_tmp` ...");
    
                database.execSQL("insert into table_tmp (`id`, `name` , ...");
    
                database.execSQL("DROP INDEX IF EXISTS `index_table_name`");
    
                database.execSQL("CREATE INDEX IF NOT EXISTS `index_table_name` ON `table_tmp` (`name`)");
    
                database.execSQL("DROP TABLE IF EXISTS table");
    
                database.execSQL("alter table table_tmp rename to table");
    
            }
        };
    
    0 讨论(0)
  • 2020-12-13 06:56

    None of the answers are correct in any of the links. After much experiments, found a way for it. The ALTER query needs to be written in the following way to make it work:

    database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL DEFAULT 0")
    

    However, the Integer DEFAULT value can be anything.

    If you want to add String type column, add in the following manner:

    database.execSQL("ALTER TABLE 'user' ADD COLUMN 'address' TEXT")
    

    This works like a charm.

    0 讨论(0)
  • 2020-12-13 06:59

    The error message is hard to parse, but there's a difference:

    TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=[]} Found:

    Found

    TableInfo{ name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=[]}

    Age is nullable but Room expected it to be not null.

    Change your migration to:

    database.execSQL("ALTER TABLE 'user' ADD COLUMN 'age' INTEGER NOT NULL");
    

    Since this exception explanation is VERY difficult to parse, I have created a small script that does the diff for you.

    Example:

    mig "java.lang.IllegalStateException: Migration failed. expected:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, age=Column{name='age', type='INTEGER', notNull=true, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}}, foreignKeys=[]} , found:TableInfo{name='user', columns={name=Column{name='name', type='TEXT', notNull=false, primaryKeyPosition=0}, id=Column{name='id', type='INTEGER', notNull=true, primaryKeyPosition=1}, age=Column{name='age', type='INTEGER', notNull=false, primaryKeyPosition=0}}, foreignKeys=[]}"
    

    Result:

    0 讨论(0)
提交回复
热议问题