1

我对这个问题有点迷茫。

Pre-packaged database has an invalid schema错误具有以下输出:

预期的

TableInfo{name='account', columns={client_alt_phone_on_route_sheets=Column{name='client_alt_phone_on_route_sheets', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='0'}, client_titles_on_address_labels=Column{name='client_titles_on_address_labels', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='0'}, client_titles_on_invoices=Column{name='client_titles_on_invoices', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='0'}}, foreignKeys=[], indices=[]}

成立

TableInfo{name='account', columns={client_alt_phone_on_route_sheets=Column{name='client_alt_phone_on_route_sheets', type='BOOLEAN', affinity='1', notNull=true, primaryKeyPosition=0, defaultValue='FALSE'}, client_titles_on_address_labels=Column{name='client_titles_on_address_labels', type='BOOLEAN', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='FALSE'}, client_titles_on_invoices=Column{name='client_titles_on_invoices', type='BOOLEAN', affinity='1', notNull=false, primaryKeyPosition=0, defaultValue='FALSE'}}, foreignKeys=[], indices=[]}

我省略了其他一些列,因为它们不是问题并且它们的输出匹配。问题在于预期INTEGER但找到的列BOOLEAN

数据库架构如下:

CREATE TABLE account
(
    client_alt_phone_on_route_sheets  BOOLEAN DEFAULT FALSE NOT NULL,
    client_titles_on_address_labels   BOOLEAN DEFAULT FALSE,
    client_titles_on_invoices         BOOLEAN DEFAULT FALSE,
    // Omitted rows
);

最初,我确实使用以下类型的列创建了accountRoom :@EntityBOOLEANBoolean

@Entity(tableName = "account")
data class Account(
    // Omitted data
    // @FIXME
    @ColumnInfo(name = "client_alt_phone_on_route_sheets", defaultValue = "FALSE") val routeSheetsClientAltPhone: Boolean,

    // @FIXME
    @ColumnInfo(name = "client_titles_on_address_labels", defaultValue = "FALSE") val clientTitlesOnAddressLabels: Boolean?,

    // @FIXME
    @ColumnInfo(name = "client_titles_on_invoices", defaultValue = "FALSE") val clientTitlesOnInvoices: Boolean?,
)

然后,第一次抛出错误时,我确实将Boolean类型列更改为Int类型:

@Entity(tableName = "account")
data class Account(
    // Omitted data
    // @FIXME
    @ColumnInfo(name = "client_alt_phone_on_route_sheets", defaultValue = "0") val routeSheetsClientAltPhone: Int,

    // @FIXME
    @ColumnInfo(name = "client_titles_on_address_labels", defaultValue = "0") val clientTitlesOnAddressLabels: Int?,

    // @FIXME
    @ColumnInfo(name = "client_titles_on_invoices", defaultValue = "0") val clientTitlesOnInvoices: Int?,
)

但是,错误不断发生。我尝试使用此答案迁移单个列,以查看它是否与预期/找到的输出匹配。

        private val MIGRATION_1_2 = object : Migration(1,2) {
            override fun migrate(database: SupportSQLiteDatabase) {
                database.execSQL(
                    "ALTER TABLE account ADD COLUMN client_alt_phone_on_route_sheets INTEGER NOT NULL DEFAULT(0)"
                )
            }
        }

        private fun buildDatabase(context: Context) = Room.databaseBuilder(
            context.applicationContext,
            Database::class.java,
            Constants.DATABASE_NAME
        ).addMigrations(MIGRATION_1_2).createFromAsset("database.db").build()

但显然迁移不起作用,也没有改变输出中的任何内容,因为错误仍然相同。另外,我不确定哪个是 Room 数据库,哪个是资产数据库。我的直觉是,“找到”输出是与资产匹配的输出,因为BOOLEAN类型不同,但这并不完全清楚。为什么将 Room@ColumnInfo值类型从 Boolean 更改为 Int 似乎没有生效?如果需要为BOOLEAN我的数据库上的每一列类型实现上述迁移,那么为多个表应用迁移的正确方法是什么?(因为我有更多具有这种BOOLEAN类型的表,尽管它们不在错误中)

4

1 回答 1

1

为什么将 Room @ColumnInfo 值类型从 Boolean 更改为 Int 似乎没有生效?

因为对于 Room,它们与任何类型 Long/long -> Boolean 的类型相同,它是一个整数(与十进制相反),在创建表 SQL 中被赋予了 INTEGER 列类型。

Room 只会创建 INTEGER、TEXT、REAL 或 BLOB 的列类型。

然而,SQLite 很灵活,因为您可以创建几乎任何类型的列(只要该类型不破坏解析器规则,例如作为关键字)。SQLite 然后使用一组规则来分配类型关联(上面列出的 4 个之一或包罗万象的 NUMERIC(哪个房间不支持/允许))。

所以从上面看,问题出在预打包的数据库上。也就是说,预打包的数据库有一个用 BOOLEAN 定义的列,房间需要INTEGER,因此您必须将列类型从 BOOLEAN 更改为 INTEGER。

您可以使用以下方法进行此更改:-

ALTER TABLE account RENAME TO account_old;
CREATE TABLE IF NOT EXISTS account (client_alt_phone_on_route_sheets INTEGER NOT NULL DEFAULT VALUE false,  .....);
INSERT INTO account SELECT * FROM account_old;
DROP TABLE IF EXISTS account_old;
  • 请注意,如果您在创建实体和带有在实体列表中定义的实体的 @Database 注释类之后编译项目,则可以从房间获取 CREATE TABLE SQL。
  • 编译成功后,Room 将在类中生成一些 java 代码,该类的名称与 @Database 注释类相同,但后缀为_Impl。在这个类中将有一个方法createAllTables用于创建表(索引和视图)的 SQL。这个 SQL 是房间所期望的

您可以在多个地方更改表格,最简单的是:-

  1. 在预打包的数据库中进行更改(如上),然后将更改的文件复制到 assets 文件夹中,或者
  2. 使用prePackagedDatabaseCallback回调请参阅如何使用 Room 的 prepackagedDatabaseCallback? 2. 在复制文件之后但在执行验证(预期 v 找到)之前调用回调。
于 2022-01-28T20:25:49.830 回答