使用带有 room 的压缩预填充数据库

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

我有一个带有 sqlite_zstd 的压缩数据库,我想在带有房间数据库的 Android 应用程序中使用它。

知道android中的sqlite的发布版本不支持扩展,requery/sqlite_android用于加载sqlite_zstd的扩展。

挑战

当我将其用作房间的预打包数据库时,数据库表在压缩后不会保持不变,并且列类型不匹配

错误

java.lang.IllegalStateException: Pre-packaged database has an invalid schema: Dictionary(com.ayitinya.englishdictionary.data.test.LocalTest).
                                                                                                     Expected:
                                                                                                    TableInfo{name='Dictionary', columns={data=Column{name='data', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='undefined'}}, foreignKeys=[], indices=[]}
                                                                                                     Found:
                                                                                                    TableInfo{name='Dictionary', columns={id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}, data=Column{name='data', type='', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='undefined'}}, foreignKeys=[], indices=[]}
@Entity(tableName = "Dictionary")
data class LocalTest(
    @ColumnInfo(name = "id") @PrimaryKey(autoGenerate = true) val wordId: Int,
    @ColumnInfo(name = "data") val word: String,
)

我用来在 python 中创建数据库的命令,因为我循环遍历 json,删除不需要的内容并将其存储在数据库中以供只读

 cursor.execute(
        """
            CREATE TABLE IF NOT EXISTS Dictionary (
                id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
                data TEXT NOT NULL
            )
        """
    )

...

   cursor.execute(f'SELECT zstd_enable_transparent(\'{{"table": "Dictionary", "column": "data", "compression_level": 19, "dict_chooser": "\'\'a\'\' || (id / 1000000)"}}\');')
    cursor.execute("SELECT zstd_incremental_maintenance(null, 1)")
    cursor. Execute("VACUUM")

...

第一个问题

当在 id 上使用 NOT NULL 创建数据库时,为什么 room 将我的主键 (id) 显示为可为空

还有第二个

如何将房间中的数据库架构与预填充的数据库架构进行匹配,因为压缩完成后我无法控制架构

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

当在 id 上使用 NOT NULL 创建数据库时,为什么 room 将我的主键 (id) 显示为可为空

不确定,但使用 Room 库 2.5.2 和 kapt 使用 LocalTest 类 asis,然后 Room 会生成(,因此期望)以下内容:-

_db.execSQL("CREATE TABLE IF NOT EXISTS `Dictionary` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `data` TEXT NOT NULL)");
  • 这反映了 Room 的期望
  • 上面的内容可以在类的 createAllTables 函数中找到,该类与 java( generated) 中的
    @Database
    注解类同名,但后缀为 _Impl 。通过 Android 视图
  • 可见

然而,该消息指出的实际问题是 Room 期望

  1. data 列具有
    NOT NULL
    约束。和
  2. id 列作为主键。

将消息拆分为列并比较显示(预期后跟找到):-

name='data', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='undefined'
name='data', type='', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='undefined'
  • 即Room 的 data 列应该具有 NOT NULL 约束。然而,找到的 data 列可以为空。

和:-

name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='undefined'
name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='undefined'
  • id列不是主键
  • 的一部分

猜测,实际的数据库不是根据您的 CREATE 语句创建的(它是否已经存在???)。建议使用 SQLite 工具来查看正在打包的实际数据库文件。

如何将房间中的数据库架构与预填充的数据库架构进行匹配,因为压缩完成后我无法控制架构

prePackagedDatabase
回调可用于转换数据库(即按预期创建表并从不兼容的表加载它)。

更多精彩敬请关注

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