桌子上的房间异常:预打包的数据库具有无效的架构
Posted
技术标签:
【中文标题】桌子上的房间异常:预打包的数据库具有无效的架构【英文标题】: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)。 预期的: TableInfoname='ItemDb', columns=scheduledTime=Columnname='scheduledTime', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null', subtype= Columnname='subtype', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null', data3=Columnname='data3', type='TEXT' ,affinity='2',notNull=false,primaryKeyPosition=0,defaultValue='null',data2=Columnname='data2',type='TEXT',affinity='2',notNull=false,primaryKeyPosition= 0,defaultValue='null',data1=Columnname='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=Columnname='_id',type='INTEGER',affinity ='3',notNull=false,primaryKeyPosition=1,defaultValue='null',type=Columnname='type',type='TEXT',affinity='2',notNull=true,primaryKeyPosition=0, defaultValue='null',foreignKeys=[],indices=[] 成立: TableInfoname='ItemDb', columns=scheduledTime=Columnname='scheduledTime', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null', subtype= Columnname='subtype', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null', data3=Columnname='data3', type='TEXT' ,affinity='2',notNull=false,primaryKeyPosition=0,defaultValue='null',data2=Columnname='data2',type='TEXT',affinity='2',notNull=false,primaryKeyPosition= 0,defaultValue='null',data1=Columnname='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=Columnname='_id',type='integer',affinity ='3',notNull=false,primaryKeyPosition=1,defaultValue='null',type=Columnname='type',type='TEXT',affinity='2',notNull=false,primaryKeyPosition=0, defaultValue='null',foreignKeys=[],indices=[]
通过比较两者,我可以看到一些字段应该被标记为notNull
,但它们似乎被标记为nullable
,而不是即使 Kotlin 类将这些字段声明为@987654328 @ 避免使用可以为空的?
。
我做错了什么? 如果您需要有关数据库体系结构的更多信息,我可以轻松地提供它们。谢谢!
【问题讨论】:
【参考方案1】:在错误消息中,“预期”架构是 Room 根据您的 Kotlin 声明 ItemDb
创建的。它正确地将type
、subType
、scheduledTime
和iteration
显示为非空列,而所有其他列都可以为空。
我没有使用过 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 类,它代表我们在应用程序中需要的对象,带有 nullable
和 not nullable
字段。)谢谢,超级有帮助!
以上是关于桌子上的房间异常:预打包的数据库具有无效的架构的主要内容,如果未能解决你的问题,请参考以下文章