Kotlin,预打包数据库有一个无效的模式:列顺序错误?

Kotlin, Pre-packaged database has an invalid schema: Column order is wrong?

我从模拟器导出了数据库的副本,并将测试数据库移动到外部文件。这一段时间以来一直运行良好,但是,今天发生了一些变化,出现了这个错误。

预打包的数据库有一个无效的模式:tableLinkUserToPassword

预计:

TableInfo 
{ 
    name='tableLinkUserToPassword', 
    columns = { 
                  userId = Column { name='userId', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null' },
                  password = Column { name='password', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null' }
    }, 
    foreignKeys = [ForeignKey 
                   {
                       referenceTable='tableUser', onDelete='CASCADE', onUpdate='NO ACTION', columnNames=[userId], referenceColumnNames=[userId]
                   }
                  ], 
    indices = [Index { name='index_tableLinkUserToPassword_password', unique=false, columns=[password], orders=[ASC] }, 
               Index { name='index_tableLinkUserToPassword_userId', unique=false, columns=[userId], orders=[ASC]}
              ]
}

找到:

    TableInfo{name='tableLinkUserToPassword', columns={password=Column{name='password', type='TEXT', affinity='2', notNull=false, primaryKeyPosition=0, defaultValue='null'}, userId=Column{name='userId', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}}, foreignKeys=[ForeignKey{referenceTable='tableUser', onDelete='CASCADE', onUpdate='NO ACTION', columnNames=[userId], referenceColumnNames=[userId]}], indices=[Index{name='index_tableLinkUserToPassword_userId', unique=false, columns=[userId], orders=[ASC]}, Index{name='index_tableLinkUserToPassword_password', unique=false, columns=[password], orders=[ASC]}]}

UserIdPassword 列顺序交换。和notNull=false好像不匹配。

我有 DB Browser,但我该如何更改顺序或列?

实体:

import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey

@Entity(
    tableName = "tableLinkUserToPassword",
    foreignKeys = [
        ForeignKey(
            entity = EntityUser::class,
            parentColumns = ["userId"],
            childColumns = ["userId"],
            onDelete = ForeignKey.CASCADE
        )
    ]
)

data class EntityLinkUserToPassword(
    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(index = true)
    val userId: Int,
    val password: String,
    )

感谢您的帮助

列出现的顺序不是问题,而是提取它们的顺序(我认为)。重要的是报告的值。

但是,可以看出,举个例子,就是密码 EXPECTED 列(从注释为 class 的 @Entity 中提取的内容)具有 NOT NULL 约束(即它不能为空)根据 notNull=true,同时它发现 FOUND 中的密码列没有编码的 NOT NULL 约束(即 pre-packaged 数据库)根据 notNull=false.

所以您要么必须更改 EntityLinkUserToPassword class 以允许空值,要么更改 pre-packaged 数据库以在密码列上编码为 NOT NULL .

例如val password: String?,

您需要检查所有列中发现的和预期的差异。

P.S。 userId 列上的第二个索引既浪费又低效。 PrimaryKey 是一个索引。所以不需要 @ColumnInfo 注释。

但是,pre-packaged 数据库的第二个索引又出现在密码列上。所以你应该移动 @ColumnInfo 注释以应用于密码 val/column 例如我相信你想要:-

data class EntityLinkUserToPassword(
    @PrimaryKey(autoGenerate = true)
    val userId: Int,
    @ColumnInfo(index = true)
    val password: String?,
    )
  • 注意以上为观察所得,建议代码未经测试不一定全面,可能有遗漏或错误。

I have DB Broswer but how would I chnage the order or columns?

你would/could:-

  1. 重命名 EntityLinkUserToPassword table 例如ALTER TABLE EntityLinkUserToPassword RENAME TO renamed_EntityLinkUserToPassword;
  2. 使用UPDATE renamed_EntityLinkUserToPassword SET password = 'a suitable default value' WHERE password IS NULL;
    1. 这样您在复制数据时就不会遇到 NOT NULL 约束冲突。
  3. 使用正确的架构创建新的 table(见下文)
  4. 使用INSERT INTO EntityLinkUserToPassword SELECT * FROM renamed_EntityLinkUserToPassword ORDER BY userId ASC;
  5. DROP TABLE IF EXISTS renamed_EntityLinkUserToPassword'

获取正确的架构

  1. 使用 @Entity 注释的 classes 根据需要编码并在 @Database 注释的实体参数中定义,编译项目。
  2. 使用 Android View in Android Studio 查看 Java(generated) for a class same名称作为 @Database 注释 class 但后缀为 _Impl.
  3. 寻找createAllTables方法。用于创建 table 的 SQL 是硬编码的。复制它,这将是精确的 SQL.