我正在尝试制作一个需要保存大量信息的应用程序,例如有关城市及其地点的数据库。 目前,我正在使用 SQLite 文件将此数据从服务器发送到客户端 - 它在服务器和客户端上都以这种方式存储,因此我想避免将其来回转换为 json,更不用说增加的有效负载大小。 应用程序下载该文件,然后使用 Room
createFromFile
方法打开它。
但每当我向表中添加新列时,Room 都会抛出:
预打包数据库的架构无效
对于必需但缺失的字段,此错误是完全可以理解的 - 但如果添加了字段,它也会抛出该错误,这不会影响现有查询。 是的,理想情况下,客户可以在 API 更改的同时更新应用程序,但我想更优雅地处理它,允许他们使用现有版本和现有功能以及更新提醒,而不是完全阻止应用程序。 所以/TLDR:
有没有办法告诉 Room 忽略 shema 中它不期望的列? 或者也许是一种自动删除意外列的方法(最好不要在常量中列出每个表和列,并手动更新每个版本的列表)
有没有办法告诉 Room 忽略 shema 中它不期望的列
Room 非常严格,实体参数中定义的任何
@Entity
带注释的类都必须完全匹配。也就是说,在编译项目时生成并编码预期的模式(其哈希值),然后运行时的代码提取实际模式,对其进行哈希处理并将其与编译的哈希值进行比较。
或者也许是一种自动删除意外列的方法(最好不要在常量中列出每个表和列,并手动更新每个版本的列表)
也许取决于您认为手动编码过多。通过复制和粘贴编译时生成的代码可以确定大部分编码。也就是说 Room 将创建 Java 代码来创建表,其中包括
CREATE ....
Room 期望的所有表和索引的 SQL。
此生成的代码可以在
Java (generated)
文件夹中找到,在 Android Studio 的 Android
视图中可见。它将位于与用 @Database
注解但带有 _Impl
后缀的类相同的类中。 createAllTables
方法包含执行 SQL 的语句。
例如以下项目有一个名为
TheDatabase
的类,并用 @Database(entities = [Note::class,Label::class,NoteLabel::class], version = 1, exportSchema = false)
进行注释
所以有:-
现在,如果您基本上复制了 SQL 并执行了每一行,但更改了表名称。然后,您将获得预期的架构,其中包含错误命名的表。使用此功能可以通过询问预期的表并将它们与通过包复制的表进行比较并生成 SQL 来填充然后重命名与 Room 预期匹配的表来实现自动转换。
您可以利用
prePackagedDatabase
回调来执行此操作。
您可能会发现如何使用 Room 预先打包的DatabaseCallback?很有用。