【问题标题】:Room exception on table: Pre-packaged database has an invalid schema桌子上的房间异常:预打包的数据库具有无效的架构
【发布时间】:2020-09-15 16:18:07
【问题描述】:

我的任务是将我们应用程序的当前架构(使用 Cupboard)迁移到 Room,我在第一项工作中遇到了一些问题,即迁移数据库对象,目前用 Java 编写(Cupboard 仅支持Java),使它们与 Room 一起工作。这是一个例子:

public class ItemDb {

public Long _id;
public String type;
public String subtype;
public long scheduledTime;
public int iteration;
public String data1;
public String data2;
public String data3;

这就是它在数据库中的样子:

我对这个实体所做的是在 Kotlin 中创建一个 @Entity 类以在 Room 中使用,它看起来像这样:

@Entity(tableName = "ItemDb")
data class ItemDb(
        @PrimaryKey(autoGenerate = true)
        val _id: Long? = 0,
        val type: String,
        val subtype: String,
        val scheduledTime: Long,
        val iteration: Int,
        val data1: String? = null,
        val data2: String? = null,
        val data3: String? = null
)

每当我尝试查询数据库时,我都会收到此异常:

预打包数据库的架构无效:ItemDb(com.example.room.model.items.ItemDb)。 预期的: TableInfo{name='ItemDb', columns={scheduledTime=Column{name='scheduledTime', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, subtype= Column{name='subtype', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, data3=Column{name='data3', type='TEXT' ,affinity='2',notNull=false,primaryKeyPosition=0,defaultValue='null'},data2=Column{name='data2',type='TEXT',affinity='2',notNull=false,primaryKeyPosition= 0,defaultValue='null'},data1=Column{name='data1',type='TEXT',affinity='2',notNull=false,primaryKeyPosition=0,defaultValue='null'},迭代=Column{ name='iteration',type='INTEGER',affinity='3',notNull=true,primaryKeyPosition=0,defaultValue='null'},_id=Column{name='_id',type='INTEGER',affinity ='3',notNull=false,primaryKeyPosition=1,defaultValue='null'},type=Column{name='type',type='TEXT',affinity='2',notNull=true,primaryKeyPosition=0, defaultValue='null'}},foreignKeys=[],indices=[]} 成立: TableInfo{name='ItemDb', columns={scheduledTime=Column{name='scheduledTime', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}, subtype= Column{name='subtype', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, data3=Column{name='data3', type='TEXT' ,affinity='2',notNull=false,primaryKeyPosition=0,defaultValue='null'},data2=Column{name='data2',type='TEXT',affinity='2',notNull=false,primaryKeyPosition= 0,defaultValue='null'},data1=Column{name='data1',type='TEXT',affinity='2',notNull=false,primaryKeyPosition=0,defaultValue='null'},迭代=Column{ name='iteration',type='INTEGER',affinity='3',notNull=false,primaryKeyPosition=0,defaultValue='null'},_id=Column{name='_id',type='integer',affinity ='3',notNull=false,primaryKeyPosition=1,defaultValue='null'},type=Column{name='type',type='TEXT',affinity='2',notNull=false,primaryKeyPosition=0, defaultValue='null'}},foreignKeys=[],indices=[]}

通过比较两者,我可以看到一些字段应该被标记为notNull,但它们似乎被标记为nullable,而不是即使 Kotlin 类将这些字段声明为@987654328 @ 避免使用可以为空的?

我做错了什么? 如果您需要有关数据库体系结构的更多信息,我可以轻松地提供它们。谢谢!

【问题讨论】:

    标签: android sqlite android-room android-database


    【解决方案1】:

    在错误消息中,“预期”架构是 Room 根据您的 Kotlin 声明 ItemDb 创建的。它正确地将typesubTypescheduledTimeiteration 显示为非空列,而所有其他列都可以为空。

    我没有使用过 Cupboard,我假设它会根据您的 ItemDb Java 声明创建一个数据库。 “找到”模式报告预打包的 Cupboard 数据库的模式,表明当 Cupboard 创建数据库时,所有列都被声明为可为空(即没有 NOT NULL)。

    要使用预打包的数据库,您需要perform a migration step 创建一个新表,并为适用的字段指定NOT NULL。然后,您需要将预打包数据库中 ItemDb 表中的所有行复制到新表中,并重新命名一些表(参见下面的示例)。

    新表的创建语句是这样的:

    CREATE TABLE new_ItemDb (_id INTEGER PRIMARY KEY AUTOINCREMENT,
        type INTEGER NOT NULL, subType INTEGER NOT NULL, scheduledTime INTEGER NOT NULL,
        iteration INTEGER NOT NULL, data1 TEXT, data2 TEXT, data3 TEXT)
    

    迁移操作可以仿照这个从documentation for migrations复制的例子:

    // Migration from 2 to 3, Room 2.2.0
    val MIGRATION_2_3 = object : Migration(2, 3) {
        override fun migrate(database: SupportSQLiteDatabase) {
            database.execSQL("""
                    CREATE TABLE new_Song (
                        id INTEGER PRIMARY KEY NOT NULL,
                        name TEXT,
                        tag TEXT NOT NULL DEFAULT ''
                    )
                    """.trimIndent())
            database.execSQL("""
                    INSERT INTO new_Song (id, name, tag)
                    SELECT id, name, tag FROM Song
                    """.trimIndent())
            database.execSQL("DROP TABLE Song")
            database.execSQL("ALTER TABLE new_Song RENAME TO Song")
        }
    }
    

    在投入时间进行上述代码更改之前,您可以通过暂时更改 ItemDb 的 Kotlin 定义以使所有字段都可以为空,然后重新尝试使用预打包的数据库来确认我的分析。我希望导入成功。

    【讨论】:

    • 感谢您为我指明正确的方向!解决方案是保持 Java 最初所做的事情(不使用任何 notNull 注释使所有字段成为 nullable)。然而,使用Migration 它也有助于我尊重满足请求的方向(有一个 Kotlin 类,它代表我们在应用程序中需要的对象,带有 nullablenot nullable 字段。)谢谢,超级有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-03
    相关资源
    最近更新 更多