[英]Android: Testing room migration
我有一个迁移,我在其中添加了一个新列迁移定义为
val MIGRATION_20_21: Migration = object : Migration(20, 21) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE tests ADD COLUMN deleted INTEGER NOT NULL DEFAULT 0")
}
}
该领域被用作
@ColumnInfo(name = "deleted") var deleted: Boolean = false,
我有这个迁移的测试用例,看起来像
@Test
@Throws(IOException::class)
fun migrate20to21() {
var db = helper.createDatabase(TEST_DB, 20).apply {
addTestsToDatabase(this, true)
close()
}
db = helper.runMigrationsAndValidate(TEST_DB, 21, true,
MIGRATION_20_21)
var cursor = db.query("SELECT * FROM tests WHERE id = ?", arrayOf("id0"))
MatcherAssert.assertThat(cursor, Is(notNullValue()))
MatcherAssert.assertThat(cursor.moveToFirst(), `is`(true))
MatcherAssert.assertThat(cursor.getColumnIndex("deleted"), `is`(38))
MatcherAssert.assertThat(cursor.getInt(cursor.getColumnIndex("deleted")), `is`(0))
我收到错误迁移没有正确处理:测试我看到预期和找到的表信息有所不同
Expected: deleted=Column{name='deleted', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, local_created_at=Column{name='local_created_at', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}
Found: deleted=Column{name='deleted', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='0'}
为什么默认值存在差异以及当我将其定义为非空时它如何为空。
为什么默认值存在差异以及当我将其定义为非空时它如何为空
原因是“预期”是从实体派生的(在编译时),然后与正在/已经打开的实际数据库的架构(已经“找到”的内容)进行比较,因此您需要更改实体也有一个默认值 0,使用@ColumnInfo(defaultValue = "0")
。
如果没有,默认值将为空,即没有指定默认值。
@ColumnInfo
的defaultValue
是在Room 2.2.0中引入的,直到那个版本 DEFAULT 子句(我相信)被忽略并且预期/发现冲突不会出现。所以实体应该包含
@ColumnInfo(defaultValue = "0")
val deleted: Int = 0
Int = 0
, Boolean = false
修正重新更新显示:-
@ColumnInfo(name = "deleted") var deleted: Boolean = false,
那么你需要使用:-
@ColumnInfo(name = "deleted", defaultValue = "0") var deleted: Boolean = false,
重新评论
谢谢你。 当我说var deleted: Boolean = false 时,是不是和说defaultValue 不一样?
对了就不一样了。
为 var/val 设置值会在实例化对象时未提供值时设置字段的值,并有效地为对象分配默认值。
虽然defaultValue = "0"
表示列定义在表的列定义中包含DEFAULT 0
。
例如
`deleted` INTEGER NOT NULL DEFAULT 0
没有你得到
`deleted` INTEGER NOT NULL
这就是 Room EXPECTED(因为它没有defaultValue =
)在你的情况下,根据你的 ALTER 列定义是 FOUND 与预期的不同(没有 DEFAULT 所以 Room 的解释是 defaultValue = null)。
在您的情况下, defaultValue = "0" 很重要,因为 0 (false) 将用作 ALTER 之前存在的行的列的值,而 null 可能会导致运行时问题。
使用var deleted: Boolean = false
也可能很重要,因为如果在实例化对象时省略该值,它会提供默认值。
也许获得 Room 期望的最好/最简单的方法是更改您的实体,然后编译(例如 Ctrl + F9),然后检查生成的 java (在 Android Studio 中的 Android 视图中很容易看到),然后找到该类被命名为每用_Impl后缀的@Database类,然后寻找createAllTables方法,其包括预期的表定义。
例如
另一项修正案
关于评论
迁移是否使用了room创建的json文件?
不,除非使用AutoMigration 。 AutoMigration 在编译时构建迁移代码(我相信),因此它需要架构并需要 exportSchema = true 和底层 gradle 架构位置指令。
迁移实际上发生在运行时并且不需要(甚至无法访问已保存的模式,因为我认为它们未包含在 APK 中)。
我当前的版本是 24,但这个字段是在版本 21 中添加的。所以即使我添加了 default = 0,它也只会重新创建 24.json。 这个 20 到 21 的测试用例失败了,因为 21.json 没有默认值。
我怀疑这可能是由于不同版本的 Room。 在2.2.0之前, defaultValue
不是一个选项,因此在比较预期和发现时会被忽略。 请注意,此比较是在执行迁移后进行的(我相信所有迁移)。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.