简体   繁体   English

Android:测试室迁移

[英]Android: Testing room migration

I have a migration where I am adding a new column The migration is defined as我有一个迁移,我在其中添加了一个新列迁移定义为

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")

    }
}

The field is dined as该领域被用作

@ColumnInfo(name = "deleted") var deleted: Boolean = false,

And I have a test case for this migration which looks like我有这个迁移的测试用例,看起来像

@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))

I am getting the error Migration didn't properly handle: tests I see a difference in expected and found table info我收到错误迁移没有正确处理:测试我看到预期和找到的表信息有所不同

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'}

Why there is a difference in default value and how can it be null when I have defined it as not null.为什么默认值存在差异以及当我将其定义为非空时它如何为空。

Why there is a difference in default value and how can it be null when I have defined it as not null为什么默认值存在差异以及当我将其定义为非空时它如何为空

The reason is that "Expected" is derived from the Entity (at compile time) and then compared to the schema of the actual database that is being/has been opened (what has been "Found" ), so you need to change the Entity to also have a default value of 0, using the @ColumnInfo(defaultValue = "0") .原因是“预期”是从实体派生的(在编译时),然后与正在/已经打开的实际数据库的架构(已经“找到”的内容)进行比较,因此您需要更改实体也有一个默认值 0,使用@ColumnInfo(defaultValue = "0")

Without then the default value will be null ie no default value specified.如果没有,默认值将为空,即没有指定默认值。

  • The @ColumnInfo 's defaultValue was introduced in Room 2.2.0 , until that version the DEFAULT clause was (I believe) ignored and and expected/found conflict wouldn't arise. @ColumnInfodefaultValue是在Room 2.2.0中引入的,直到那个版本 DEFAULT 子句(我相信)被忽略并且预期/发现冲突不会出现。

So the Entity should contain所以实体应该包含

@ColumnInfo(defaultValue = "0")
val deleted: Int = 0
  • Or instead of Int = 0 , Boolean = false或者代替Int = 0Boolean = false

Amendment re update showing:-修正重新更新显示:-

@ColumnInfo(name = "deleted") var deleted: Boolean = false,

then you need to use :-那么你需要使用:-

@ColumnInfo(name = "deleted", defaultValue = "0") var deleted: Boolean = false,

Re the comment重新评论

thank you.谢谢你。 when I say var deleted: Boolean = false, is it not the same as saying defaultValue?当我说var deleted: Boolean = false 时,是不是和说defaultValue 不一样?

Correct it isn't the same.对了就不一样了。

Setting a value for var/val sets the value of the field when the value isn't provided when instantiating the object and effectively assigns the object a default value.为 var/val 设置值会在实例化对象时未提供值时设置字段的值,并有效地为对象分配默认值。

Whilst defaultValue = "0" says that the column definition includes the DEFAULT 0 in the table's column definition.虽然defaultValue = "0"表示列定义在表的列定义中包含DEFAULT 0

eg例如

 `deleted` INTEGER NOT NULL DEFAULT 0

Without you get没有你得到

 `deleted` INTEGER NOT NULL

This is what Room EXPECTED (as it is without defaultValue = ) in your case according to the Entity your ALTER column definition that was FOUND differs from the expected (no DEFAULT so Room's interpretation is defaultValue = null).这就是 Room EXPECTED(因为它没有defaultValue = )在你的情况下,根据你的 ALTER 列定义是 FOUND 与预期的不同(没有 DEFAULT 所以 Room 的解释是 defaultValue = null)。

In your case the defaultValue = "0" is important as 0 (false) will be used as the value for the column for rows that existed before the ALTER, whilst null might result in run time issues.在您的情况下, defaultValue = "0" 很重要,因为 0 (false) 将用作 ALTER 之前存在的行的列的值,而 null 可能会导致运行时问题。

using var deleted: Boolean = false , is also potentially important as it provides the default value if the value is omitted when instantiating the object.使用var deleted: Boolean = false也可能很重要,因为如果在实例化对象时省略该值,它会提供默认值。

  • Perhaps the best/easiest way to get things as Room expects is to make your Entity changes, then compile (eg Ctrl + F9) and to then inspect the generated java (easily visible from Android View in Android Studio) to then find the class that is named as per the @Database class suffixed with _Impl and then find the createAllTables method which includes the EXPECTED table definitions.也许获得 Room 期望的最好/最简单的方法是更改​​您的实体,然后编译(例如 Ctrl + F9),然后检查生成的 java (在 Android Studio 中的 Android 视图中很容易看到),然后找到该类被命名为每用_Impl后缀的@Database类,然后寻找createAllTables方法,其包括预期的表定义。

  • eg例如

  • 在此处输入图片说明

Another Amendment另一项修正案

Regarding the comment关于评论

Does the migration uses the json files created by room?迁移是否使用了room创建的json文件?

No, UNLESS AutoMigration is used.不,除非使用AutoMigration AutoMigration builds the code for the migration (I believe) at compile time and hence why it needs schemas and requires exportSchema = true and the underlying gradle schema location directive. AutoMigration 在编译时构建迁移代码(我相信),因此它需要架构并需要 exportSchema = true 和底层 gradle 架构位置指令。

Migrations actually take place at run time and do not need (nor even have access to the saved schemas as I believe that they are not included in the APK).迁移实际上发生在运行时并且不需要(甚至无法访问已保存的模式,因为我认为它们未包含在 APK 中)。

My current version is 24 but this field was added at version 21. SO even though I add default = 0, it only recreates 24.json.我当前的版本是 24,但这个字段是在版本 21 中添加的。所以即使我添加了 default = 0,它也只会重新创建 24.json。 This test case for 20 to 21 fails as 21.json do not have default value.这个 20 到 21 的测试用例失败了,因为 21.json 没有默认值。

I suspect that this could be due to different versions of Room.我怀疑这可能是由于不同版本的 Room。 Prior to 2.2.0 defaultValue was not an option and thus it was ignored when comparing expected and found.2.2.0之前, defaultValue不是一个选项,因此在比较预期和发现时会被忽略。 Noting that this comparison is undertaken after migration(s) have been performed (I believe ALL migrations).请注意,此比较是在执行迁移后进行的(我相信所有迁移)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM