如何让 Room 使用具有不同模式的“预打包”数据库?

问题描述 投票:0回答:1

我正在尝试制作一个需要保存大量信息的应用程序,例如有关城市及其地点的数据库。 目前,我正在使用 SQLite 文件将此数据从服务器发送到客户端 - 它在服务器和客户端上都以这种方式存储,因此我想避免将其来回转换为 json,更不用说增加的有效负载大小。 应用程序下载该文件,然后使用 Room

createFromFile
方法打开它。 但每当我向表中添加新列时,Room 都会抛出:

预打包数据库的架构无效

对于必需但缺失的字段,此错误是完全可以理解的 - 但如果添加了字段,它也会抛出该错误,这不会影响现有查询。 是的,理想情况下,客户可以在 API 更改的同时更新应用程序,但我想更优雅地处理它,允许他们使用现有版本和现有功能以及更新提醒,而不是完全阻止应用程序。 所以/TLDR:

有没有办法告诉 Room 忽略 shema 中它不期望的列? 或者也许是一种自动删除意外列的方法(最好不要在常量中列出每个表和列,并手动更新每个版本的列表)

android kotlin sqlite android-room
1个回答
0
投票

有没有办法告诉 Room 忽略 shema 中它不期望的列

Room 非常严格,实体参数中定义的任何

@Entity
带注释的类都必须完全匹配。也就是说,在编译项目时生成并编码预期的模式(其哈希值),然后运行时的代码提取实际模式,对其进行哈希处理并将其与编译的哈希值进行比较。

  • 参见下图,它包含这样一个哈希(将存储在表 room_master_table 中)。

或者也许是一种自动删除意外列的方法(最好不要在常量中列出每个表和列,并手动更新每个版本的列表)

也许取决于您认为手动编码过多。通过复制和粘贴编译时生成的代码可以确定大部分编码。也就是说 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)

进行注释

所以有:-

createAllTables

  • 请注意 room_master_table 可以(应该)被忽略。 Room 将确保它存在。它实际上包含预期模式,并用于比较实际模式与预期模式(因此出现错误/消息和您的问题)。

现在,如果您基本上复制了 SQL 并执行了每一行,但更改了表名称。然后,您将获得预期的架构,其中包含错误命名的表。使用此功能可以通过询问预期的表并将它们与通过包复制的表进行比较并生成 SQL 来填充然后重命名与 Room 预期匹配的表来实现自动转换。

  • 可以通过 sqlite_master 进行询问和/或执行合适的 PRAGMA

您可以利用

prePackagedDatabase
回调来执行此操作。

您可能会发现如何使用 Room 预先打包的DatabaseCallback?很有用。

© www.soinside.com 2019 - 2024. All rights reserved.