我正在尝试使用 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;
}
那么,可能是什么错误?确实看了很多文档,也找不到这个问题的原因。
答案 0 :(得分:3)
获取正确 SQL 的简单技巧是让 Room 代表您生成 SQL。
创建Entity(s)然后编译(Cntrl+F9)然后查看生成的java(从Android视图)然后查找与@Database类相同的后缀为_Impl的文件,然后找到createAllTables 方法和 SQL 就在那里。这正是 Room 所期望的。
例如:-
答案 1 :(得分:1)
绿色列是您的迁移应该是什么样子。
请检查突出显示的字段并进行与绿色类似的更改,因为这是您的预期结果。
这是指向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 以获得更多说明。
用于排列和比较找到的和预期的脚本:
您可以使用编程脚本对它们进行排序,但这里有一种使用一些工具对它们进行排序的方法:
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=[]}
},
替换为 },\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=[]}
现在每列都在单独的行中:
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=[]}