Adding a new column into sqlite produces an error: Exception while computing database live data
Adding a new column into sqlite produces an error: Exception while computing database live data
我有这个数据 class,我在其中添加了一个新值 requirePolice
@Entity
data class Crime(@PrimaryKey val id : UUID = UUID.randomUUID(),
var title: String ="",
var date: Date = Date(),
var isSolved: Boolean = false,
var requirePolice : Boolean = false, <--- this is the new value
var suspect: String = ""){
//designating a picture location p.317
val photoFileName
get() = "IMG_$id.jpg"
}
我将数据库从 2 升级到 3 以将其包含在 SQLite 中 table,我还保留了以前的升级代码
@Database(entities = [Crime::class], version = 3)
@TypeConverters(CrimeTypeConverters::class)
abstract class CrimeDatabase: RoomDatabase(){
abstract fun crimeDao() : CrimeDao
}
val migration_1_2 = object : Migration(1,2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Crime ADD COLUMN suspect TEXT NOT NULL DEFAULT ''")
}
}
val migration_2_3 = object : Migration(2,3){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Crime ADD COLUMN requirePolice TEXT NOT NULL DEFAULT ''")
}
}
我以这种方式将升级包含到存储库中
private const val DATABASE_NAME = "crime-database"
class CrimeRepository private constructor(context: Context){
private val database: CrimeDatabase = Room.databaseBuilder(
context.applicationContext,
CrimeDatabase::class.java,
DATABASE_NAME
).addMigrations(migration_1_2)
.addMigrations(migration_2_3)//adding latest migration
.build()
...
我一直收到这个错误
E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_0
Process: com.bignerdranch.android.criminalintent, PID: 22566
java.lang.RuntimeException: Exception while computing database live data.
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:92)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: java.lang.IllegalStateException: Migration didn't properly handle: Crime(com.bignerdranch.android.criminalintent.Crime).
Expected:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:103)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:177)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:416)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:145)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:106)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:731)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:508)
at androidx.room.RoomDatabase.query(RoomDatabase.java:551)
at androidx.room.util.DBUtil.query(DBUtil.java:83)
at com.bignerdranch.android.criminalintent.database.CrimeDao_Impl.call(CrimeDao_Impl.java:158)
at com.bignerdranch.android.criminalintent.database.CrimeDao_Impl.call(CrimeDao_Impl.java:155)
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:90)
... 3 more
为什么给我这个错误?
如何让它发挥作用?
如果你使用的是sql light db,那么你必须用这种方式迁移db,
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 4) {
db.execSQL("ALTER TABLE " + TABLE_NOTIFICATION + " ADD COLUMN " + COLUMN_DEEP_LINK + " TEXT ");
}
}
失败的原因解释在:-
Expected:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
更具体地说,预期的(实体预期的)是:-
requirePolice=Column{name='requirePolice', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}
虽然 table(找到的内容)已更改为:-
requirePolice=Column{name='requirePolice', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}
主要区别在于,ALTER 将列类型设置为 TEXT,而不是 INTEGER 列类型(布尔值等于 INTEGER)。
- 即预期 INTEGER(布尔值)找到 TEXT(字符串)
因此你需要使用 :-
val migration_2_3 = object : Migration(2,3){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Crime ADD COLUMN requirePolice INTEGER NOT NULL")
}
或将实体更改为 (可能不是您想要的):-
@Entity
data class Crime(@PrimaryKey val id : UUID = UUID.randomUUID(),
var title: String ="",
var date: Date = Date(),
var isSolved: Boolean = false,
var requirePolice : String = "", <--- this is the new value
var suspect: String = ""){
//designating a picture location p.317
val photoFileName
get() = "IMG_$id.jpg"
}
- 很可能您要更改的是 ALTER 语句而不是实体。
如何避免此类 EXPECTED/FOUND 差异 - 也就是让 Room 为您完成工作
您实际上可以确定 creating/changing 实体期望的内容,然后在成功后编译 CTRL+F9编译底层 java 生成,这实际上包含 SQL 以创建 table(s).
您可以通过选择 Android 查看来查看 SQL,找到 java(生成的)文件夹,展开它,然后展开文件夹,然后找到 class 与您的 @Database class 同名,后缀为 _Impl(CrimeDatabase_Impl 在您的例子中)在 class 中会有一个 createAllTables 方法,它包含所有 table 的 EXPECTED SQL 然后您可以 extract/copy SQL 定义更改的列并在 ALTER 语句中使用它(如果添加新实体,那么整个 table 也有 SQL)。
- 请注意,根据警告不要更改 class 中的任何内容。
这是上面的一个例子(虽然不是你的项目):-
我有这个数据 class,我在其中添加了一个新值 requirePolice
@Entity
data class Crime(@PrimaryKey val id : UUID = UUID.randomUUID(),
var title: String ="",
var date: Date = Date(),
var isSolved: Boolean = false,
var requirePolice : Boolean = false, <--- this is the new value
var suspect: String = ""){
//designating a picture location p.317
val photoFileName
get() = "IMG_$id.jpg"
}
我将数据库从 2 升级到 3 以将其包含在 SQLite 中 table,我还保留了以前的升级代码
@Database(entities = [Crime::class], version = 3)
@TypeConverters(CrimeTypeConverters::class)
abstract class CrimeDatabase: RoomDatabase(){
abstract fun crimeDao() : CrimeDao
}
val migration_1_2 = object : Migration(1,2){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Crime ADD COLUMN suspect TEXT NOT NULL DEFAULT ''")
}
}
val migration_2_3 = object : Migration(2,3){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Crime ADD COLUMN requirePolice TEXT NOT NULL DEFAULT ''")
}
}
我以这种方式将升级包含到存储库中
private const val DATABASE_NAME = "crime-database"
class CrimeRepository private constructor(context: Context){
private val database: CrimeDatabase = Room.databaseBuilder(
context.applicationContext,
CrimeDatabase::class.java,
DATABASE_NAME
).addMigrations(migration_1_2)
.addMigrations(migration_2_3)//adding latest migration
.build()
...
我一直收到这个错误
E/AndroidRuntime: FATAL EXCEPTION: arch_disk_io_0
Process: com.bignerdranch.android.criminalintent, PID: 22566
java.lang.RuntimeException: Exception while computing database live data.
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:92)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: java.lang.IllegalStateException: Migration didn't properly handle: Crime(com.bignerdranch.android.criminalintent.Crime).
Expected:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
at androidx.room.RoomOpenHelper.onUpgrade(RoomOpenHelper.java:103)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.onUpgrade(FrameworkSQLiteOpenHelper.java:177)
at android.database.sqlite.SQLiteOpenHelper.getDatabaseLocked(SQLiteOpenHelper.java:416)
at android.database.sqlite.SQLiteOpenHelper.getWritableDatabase(SQLiteOpenHelper.java:316)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper$OpenHelper.getWritableSupportDatabase(FrameworkSQLiteOpenHelper.java:145)
at androidx.sqlite.db.framework.FrameworkSQLiteOpenHelper.getWritableDatabase(FrameworkSQLiteOpenHelper.java:106)
at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:731)
at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:508)
at androidx.room.RoomDatabase.query(RoomDatabase.java:551)
at androidx.room.util.DBUtil.query(DBUtil.java:83)
at com.bignerdranch.android.criminalintent.database.CrimeDao_Impl.call(CrimeDao_Impl.java:158)
at com.bignerdranch.android.criminalintent.database.CrimeDao_Impl.call(CrimeDao_Impl.java:155)
at androidx.room.RoomTrackingLiveData.run(RoomTrackingLiveData.java:90)
... 3 more
为什么给我这个错误? 如何让它发挥作用?
如果你使用的是sql light db,那么你必须用这种方式迁移db,
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (oldVersion < 4) {
db.execSQL("ALTER TABLE " + TABLE_NOTIFICATION + " ADD COLUMN " + COLUMN_DEEP_LINK + " TEXT ");
}
}
失败的原因解释在:-
Expected:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
Found:
TableInfo{name='Crime', columns={date=Column{name='date', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, requirePolice=Column{name='requirePolice', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}, isSolved=Column{name='isSolved', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, id=Column{name='id', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=1, defaultValue='null'}, suspect=Column{name='suspect', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}, title=Column{name='title', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue='null'}}, foreignKeys=[], indices=[]}
更具体地说,预期的(实体预期的)是:-
requirePolice=Column{name='requirePolice', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}
虽然 table(找到的内容)已更改为:-
requirePolice=Column{name='requirePolice', type='TEXT', affinity='2', notNull=true, primaryKeyPosition=0, defaultValue=''''}
主要区别在于,ALTER 将列类型设置为 TEXT,而不是 INTEGER 列类型(布尔值等于 INTEGER)。
- 即预期 INTEGER(布尔值)找到 TEXT(字符串)
因此你需要使用 :-
val migration_2_3 = object : Migration(2,3){
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE Crime ADD COLUMN requirePolice INTEGER NOT NULL")
}
或将实体更改为 (可能不是您想要的):-
@Entity
data class Crime(@PrimaryKey val id : UUID = UUID.randomUUID(),
var title: String ="",
var date: Date = Date(),
var isSolved: Boolean = false,
var requirePolice : String = "", <--- this is the new value
var suspect: String = ""){
//designating a picture location p.317
val photoFileName
get() = "IMG_$id.jpg"
}
- 很可能您要更改的是 ALTER 语句而不是实体。
如何避免此类 EXPECTED/FOUND 差异 - 也就是让 Room 为您完成工作
您实际上可以确定 creating/changing 实体期望的内容,然后在成功后编译 CTRL+F9编译底层 java 生成,这实际上包含 SQL 以创建 table(s).
您可以通过选择 Android 查看来查看 SQL,找到 java(生成的)文件夹,展开它,然后展开文件夹,然后找到 class 与您的 @Database class 同名,后缀为 _Impl(CrimeDatabase_Impl 在您的例子中)在 class 中会有一个 createAllTables 方法,它包含所有 table 的 EXPECTED SQL 然后您可以 extract/copy SQL 定义更改的列并在 ALTER 语句中使用它(如果添加新实体,那么整个 table 也有 SQL)。
- 请注意,根据警告不要更改 class 中的任何内容。
这是上面的一个例子(虽然不是你的项目):-