lii*_*iil 5 android android-room
我想对我的房间数据库进行简单的更改:添加一个新表。
我的房间版本是:2.4.1
根据https://medium.com/androiddevelopers/room-auto-migrations-d5370b0ca6eb,使用自动迁移这项任务应该很容易。
这是我的数据库类的相关部分在迁移之前的样子:
@Database(
entities = [FlashCard::class, Pool::class],
version = 2
)
abstract class DB : RoomDatabase() {
...
Run Code Online (Sandbox Code Playgroud)
对于迁移,我将该部分更改为:
@Database(
entities = [FlashCard::class, Pool::class, FlashCardRunEvent::class],
version = 3,
autoMigrations = [
AutoMigration (from = 2, to = 3)
]
)
abstract class DB : RoomDatabase() {
...
Run Code Online (Sandbox Code Playgroud)
一切都编译得很好。应用程序运行直到第一次与数据库交互。
然后,应用程序崩溃了,我在日志中看到以下内容:
Caused by: java.lang.IllegalStateException: Migration didn't properly handle: FlashCardRunEvent(com.ravenala.flashy.room.FlashCardRunEvent).
Expected:
TableInfo{name='FlashCardRunEvent', columns={newBox=Column{name='newBox', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, flashCardId=Column{name='flashCardId', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, timeStampInSeconds=Column{name='timeStampInSeconds', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'}, oldBox=Column{name='oldBox', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='FlashCardRunEvent', columns={}, foreignKeys=[], indices=[]}
Run Code Online (Sandbox Code Playgroud)
我不知道该怎么办。“预期”和“发现”之间的差异是怎么回事?我原本希望 room 能够简单地看到新表,从中生成一个方案并创建表。像这一次一样编写 SQL 语句进行简单迁移的时代还没有结束吗?
“预期”和“发现”之间的差异是怎么回事?
预期是根据 Room 对通过 @Database 注释中的实体参数定义的类的处理的模式。
Found 是打开数据库时在数据库中找到的架构,在您的情况下是在自动迁移之后。
报告发现TableInfo{name='FlashCardRunEvent', columns={}, foreignKeys=[], indices=[]}表明FlasCardRunEvent表在自动迁移后不存在。
我原本希望 room 能够简单地看到新表,从中生成一个方案并创建表。像这一次一样编写 SQL 语句进行简单迁移的时代还没有结束吗?
从您提供的代码中看不出来为什么。当然,AutoMigration 能够创建新表(已使用简单的场景对此进行了测试)。
一切都编译得很好。
您检查构建日志是否有任何警告?这些(如果有的话)可能是有关正在发生的事情的线索。
为什么 Room 不创建表
一个推测:-
您没有因忘记运行某些内容(例如未将 FlashCardRunEvent 实体添加到 @Database 注释中的实体列表中定义的实体)而无意中绕过迁移,从而将版本增加到版本 3;然后更正了遗漏并在版本 3 时运行?
否则我不确定。查看生成的 java(通过 Android 视图可见)例如:-
这应该是这样的:-
class AppDatabase_AutoMigration_2_3_Impl extends Migration {
public AppDatabase_AutoMigration_2_3_Impl() {
super(2, 3);
}
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("CREATE TABLE IF NOT EXISTS `FlashCardRunEvent` (`id` INTEGER, `newBox` INTEGER NOT NULL, `flashCardId` INTEGER NOT NULL, `timeStampInSeconds` INTEGER NOT NULL, `oldBox` INTEGER NOT NULL, PRIMARY KEY(`id`))");
}
}
Run Code Online (Sandbox Code Playgroud)
此外,在生成的 java 中,您希望 createAllTables 方法的 DB_Impl 类中还包含 FlashCardRunEvent 表的 CREATE TABLE。
从上面可以看出,代码是从测试派生的,尽管初始表不同,但迁移 2-3 添加了 FlashCardRunEvent 表(通过根据预期构建实体类),即:-
@Entity
data class FlashCardRunEvent(
/*
TableInfo{name='FlashCardRunEvent',
columns={
newBox=Column{name='newBox', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'},
flashCardId=Column{name='flashCardId', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'},
timeStampInSeconds=Column{name='timeStampInSeconds', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'},
id=Column{name='id', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=1, defaultValue='null'},
oldBox=Column{name='oldBox', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}},
foreignKeys=[], indices=[]}
*/
@PrimaryKey
val id: Long?,
val newBox: Long,
val flashCardId: Long,
val timeStampInSeconds: Long,
val oldBox: Long
)
Run Code Online (Sandbox Code Playgroud)
测试成功创建表。一个明显的区别是我exportSchema = true在 @Database 注释中进行了编码,而不是依赖它默认为 true。
运行测试并创建 FlasCardRunEvent 表:-
| 归档时间: |
|
| 查看次数: |
1917 次 |
| 最近记录: |