房间数据库迁移:java.lang.IllegalStateException:迁移没有正确处理 <table_name>

时间:2021-04-28 20:42:46

标签: java android sqlite android-room

我正在尝试使用 Room 数据库创建一个新表。我遵循了我在程序中已有的第一个表中使用的相同原则,但是当需要运行应用程序时,我收到此错误:

Caused by: java.lang.IllegalStateException: Migration didn't properly handle: WaterFountainEntry(com.mpms.relatorioacessibilidadecortec.entities.WaterFountainEntry).
     Expected:
    TableInfo{name='WaterFountainEntry', columns={waterFountainHeight=Column{name='waterFountainHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}, waterFountainID=Column{name='waterFountainID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, cupHolderHeight=Column{name='cupHolderHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}, schoolEntryID=Column{name='schoolEntryID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, waterFountApproximation=Column{name='waterFountApproximation', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[ForeignKey{referenceTable='SchoolEntry', onDelete='CASCADE', onUpdate='CASCADE', columnNames=[schoolEntryID], referenceColumnNames=[cadID]}], indices=[]}
     Found:
    TableInfo{name='WaterFountainEntry', columns={waterFountainID=Column{name='waterFountainID', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, waterFountainHeight=Column{name='waterFountainHeight', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}, cupHolderHeight=Column{name='cupHolderHeight', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}, schoolEntryID=Column{name='schoolEntryID', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, waterFountApproximation=Column{name='waterFountApproximation', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[ForeignKey{referenceTable='SchoolEntry', onDelete='NO ACTION', onUpdate='NO ACTION', columnNames=[schoolEntryID], referenceColumnNames=[cadID]}], indices=[]}

通过阅读此错误消息,我确实认为程序期望某些字段的类型不同(并且可能也有不同的顺序),但事实是它不应该是那样的。我确保完全按照我将字段放入实体中的方式编写迁移类,如下所示:

<Migration Class and Database Creation>

 static final Migration MIGRATION_2_3 = new Migration(2,3) {
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) {
            database.execSQL("CREATE TABLE WaterFountainEntry (waterFountainID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL," +
                    "schoolEntryID INTEGER NOT NULL, waterFountainHeight DOUBLE NOT NULL, cupHolderHeight DOUBLE NOT NULL," +
                    "waterFountApproximation DOUBLE NOT NULL, FOREIGN KEY (schoolEntryID) REFERENCES SchoolEntry (cadID))");
        }
    };

    public static ReportDatabase getDatabase(final Context context) {
        if (INSTANCE == null){
            synchronized (ReportDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(), ReportDatabase.class, "ReportDatabase")
                            .addCallback(roomCallback).addMigrations(MIGRATION_2_3).build();
                }
            }
        }
        return INSTANCE;
    }

<WaterFountainEntry entity>

@Entity(foreignKeys = @ForeignKey(entity = SchoolEntry.class, parentColumns = "cadID", childColumns = "schoolEntryID",
        onDelete = CASCADE, onUpdate = CASCADE))
public class WaterFountainEntry {

    @PrimaryKey(autoGenerate = true)
    @NonNull
    private Integer waterFountainID;
    @NonNull
    private Integer schoolEntryID;
    @NonNull
    private Double waterFountainHeight;
    @NonNull
    private Double cupHolderHeight;
    @NonNull
    private Double waterFountApproximation;

/** getters & setters **/

    public WaterFountainEntry(@NonNull Integer schoolEntryID, @NonNull Double waterFountainHeight,
                              @NonNull Double cupHolderHeight, @NonNull Double waterFountApproximation) {
        this.schoolEntryID = schoolEntryID;
        this.waterFountainHeight = waterFountainHeight;
        this.cupHolderHeight = cupHolderHeight;
        this.waterFountApproximation = waterFountApproximation;
    }

那么,可能是什么错误?确实看了很多文档,也找不到这个问题的原因。

3 个答案:

答案 0 :(得分:3)

获取正确 SQL 的简单技巧是让 Room 代表您生成 SQL。

创建Entity(s)然后编译(Cntrl+F9)然后查看生成的java(从Android视图)然后查找与@Database类相同的后缀为_Impl的文件,然后找到createAllTables 方法和 SQL 就在那里。这正是 Room 所期望的。

例如:-

enter image description here

答案 1 :(得分:1)

绿色列是您的迁移应该是什么样子。

enter image description here

请检查突出显示的字段并进行与绿色类似的更改,因为这是您的预期结果。

这是指向diff checker的链接以供比较

只需比较找到的结果和预期的结果,您就会知道在迁移过程中需要做哪些更改

 Expected:
    TableInfo{name='WaterFountainEntry', columns={waterFountainHeight=Column{name='waterFountainHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}, waterFountainID=Column{name='waterFountainID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, cupHolderHeight=Column{name='cupHolderHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}, schoolEntryID=Column{name='schoolEntryID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, waterFountApproximation=Column{name='waterFountApproximation', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[ForeignKey{referenceTable='SchoolEntry', onDelete='CASCADE', onUpdate='CASCADE', columnNames=[schoolEntryID], referenceColumnNames=[cadID]}], indices=[]}
     Found:
    TableInfo{name='WaterFountainEntry', columns={waterFountainID=Column{name='waterFountainID', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'}, waterFountainHeight=Column{name='waterFountainHeight', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}, cupHolderHeight=Column{name='cupHolderHeight', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}, schoolEntryID=Column{name='schoolEntryID', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, waterFountApproximation=Column{name='waterFountApproximation', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[ForeignKey{referenceTable='SchoolEntry', onDelete='NO ACTION', onUpdate='NO ACTION', columnNames=[schoolEntryID], referenceColumnNames=[cadID]}], indices=[]}

答案 2 :(得分:1)

预期&找到的SQL脚本有很多不同;以 cupHolderHeight 列为例:

cupHolderHeight 列:

  • 预期:REAL 发现:DOUBLE --> 将其更改为 REAL(基本上 SQLite 中没有 DOUBLE 类型)
  • 预期 notNull=false,找到 notNull=true --> 将其更改为 false(即 NULL)

将其应用于您的迁移 SQL 脚本:

cupHolderHeight DOUBLE NOT NULL改成cupHolderHeight REAL

您需要浏览其他列并执行相同操作。最终脚本应该是这样的:

database.execSQL("CREATE TABLE WaterFountainEntry (waterFountainID INTEGER PRIMARY KEY AUTOINCREMENT," +
                    "schoolEntryID INTEGER, waterFountainHeight REAL, cupHolderHeight REAL," +
                    "waterFountApproximation REAL, FOREIGN KEY (schoolEntryID) REFERENCES SchoolEntry (cadID) ON UPDATE CASCADE ON DELETE CASCADE)");

您也可以考虑 this answer 以获得更多说明。

用于排列和比较找到的和预期的脚本:

您可以使用编程脚本对它们进行排序,但这里有一种使用一些工具对它们进行排序的方法:

  1. 将第一个(预期)复制到文本编辑器中:
TableInfo{name='WaterFountainEntry', columns={waterFountainHeight=Column{name='waterFountainHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}, waterFountainID=Column{name='waterFountainID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, cupHolderHeight=Column{name='cupHolderHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}, schoolEntryID=Column{name='schoolEntryID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, waterFountApproximation=Column{name='waterFountApproximation', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[ForeignKey{referenceTable='SchoolEntry', onDelete='CASCADE', onUpdate='CASCADE', columnNames=[schoolEntryID], referenceColumnNames=[cadID]}], indices=[]}
  1. }, 替换为 },\n --> 您必须知道如何在文本编辑器中添加换行符:
TableInfo{name='WaterFountainEntry', columns={waterFountainHeight=Column{name='waterFountainHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'},
waterFountainID=Column{name='waterFountainID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'},
cupHolderHeight=Column{name='cupHolderHeight', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'},
schoolEntryID=Column{name='schoolEntryID', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'},
waterFountApproximation=Column{name='waterFountApproximation', type='REAL', affinity='4', notNull=false, primaryKeyPosition=0, defaultValue='null'}},
foreignKeys=[ForeignKey{referenceTable='SchoolEntry', onDelete='CASCADE', onUpdate='CASCADE', columnNames=[schoolEntryID], referenceColumnNames=[cadID]}], indices=[]}

现在每列都在单独的行中:

  1. 为另一个(找到)做 1 和 2:
TableInfo{name='WaterFountainEntry', columns={waterFountainID=Column{name='waterFountainID', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null'},
waterFountainHeight=Column{name='waterFountainHeight', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'},
cupHolderHeight=Column{name='cupHolderHeight', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'},
schoolEntryID=Column{name='schoolEntryID', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'},
waterFountApproximation=Column{name='waterFountApproximation', type='DOUBLE', affinity='4', notNull=true, primaryKeyPosition=0, defaultValue='null'}},
foreignKeys=[ForeignKey{referenceTable='SchoolEntry', onDelete='NO ACTION', onUpdate='NO ACTION', columnNames=[schoolEntryID], referenceColumnNames=[cadID]}], indices=[]}
  1. 现在可以轻松地按字母顺序对它们进行排序并将一个值与另一个值进行比较(Excel 可以成为此方面的工具)。