房间数据库迁移:java.lang.IllegalStateException:迁移没有';t正确处理<;表_name>;

房间数据库迁移:java.lang.IllegalStateException:迁移没有';t正确处理<;表_name>;,java,android,sqlite,android-room,Java,Android,Sqlite,Android Room,我正在尝试使用Room数据库创建一个新表。我遵循的原则与我在程序中已有的第一个表相同,但当运行应用程序时,我会出现以下错误: Caused by: java.lang.IllegalStateException: Migration didn't properly handle: WaterFountainEntry(com.mpms.relatorioacessibilidadecortec.entities.WaterFountainEntry). Expected: Ta

我正在尝试使用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=[]}
通过阅读此错误消息,我确实收集到程序希望某些字段的类型不同(可能顺序也不同),但问题是它不应该是这样的。我确保完全按照我在实体中放置字段的方式编写迁移类,如下所示:


那么,错误是什么呢?我真的读了很多文档,找不到这个问题的原因。

绿色栏就是迁移的样子

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

这里是到的链接以供比较

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

 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=[]}

预期和找到的SQL脚本之间存在许多差异;以
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)");
<>你也可以考虑更多的说明。

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

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

  • 将第一个(预期)复制到文本编辑器中:
  • },
    替换为
    },\n
    -->您必须知道如何在文本编辑器中添加换行符:
  • 现在,您将把每一列放在一个单独的行中:

  • 对另一个(找到的)执行1和2:
  • 现在很容易按字母顺序对它们进行排序,并将一个值与另一个值进行比较(Excel可以作为一种工具)

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

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

    e、 g:-


    如果您先按相同的顺序重新排列列,您将获得更好的差异(Room不关心顺序),那么,我如何重新排列列?我在研究时找不到任何类似的东西。如果你看图片,列的顺序是不同的。在第一幅图像中,WaterCountainId是第一列,但在第二幅图像中,WaterCountainHeight是第一列。如果可以对它们进行重新排序,则比较差异会很容易。重新排序错误文本与代码无关。@CorMatt我已为您更新了图像如果我直接从实体创建表,则无法在创建实体时使用“真实”值。将
    Double
    更改为
    Real
    不会在迁移类中产生任何问题?您可以在entity中正常使用
    Double
    ,Room database将在
    Real
    Double
    之间来回转换,但在
    database.execSQL()
    中需要编写SQL脚本而不是java脚本
     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=[]}
    
    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)");
    
    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={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=[]}