在将Android-Room版本从2.2.x更新到2.4.x后,我决定使用自动迁移功能来帮助我编写更少的代码。因此,我想弃用所有手动编写的迁移,而改用自动迁移。但是我在使用自动迁移时遇到错误:
// Compile Time Error:
// New NOT NULL column'height' added with no default value specified.
// Please specify the default value using @ColumnInfo.
@ColumnInfo(name = "height")
val height: Long = 0L
即使我以这种方式指定了默认值,但仍然得到相同的错误:
@ColumnInfo(name = "height", defaultValue = "0")
val height: Long = 0L
我的代码有什么问题,如何修复此错误?
我有两个版本数据库:
版本 1
@Entity(tableName = "user")
data class User(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Long = 0L,
@ColumnInfo(name = "name")
val name: String = ""
)
@Database(
entities = [User::class],
version = 1
)
abstract class UserDB : RoomDatabase()
然后在版本2中,我在用户表中添加了一个名称为“高度”的列:
版本2
@Entity(tableName = "user")
data class User(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Long = 0L,
@ColumnInfo(name = "name")
val name: String = "",
@Column(name = "height")
val height: Long = 0L
)
@Database(
entities = [User::class],
version = 2
)
abstract class UserDB : RoomDatabase() {
object ManualMigrations {
val M_1_2 = object : Migration(1, 2) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("ALTER TABLE user ADD COLUMN height INTEGER NOT NULL DEFAULT 0")
}
}
}
}
现在我想弃用所有手动迁移并改用自动迁移。我更改了代码并收到错误:
// Compile Time Error:
// New NOT NULL column'height' added with no default value specified.
// Please specify the default value using @ColumnInfo.
@Database(
entities = [User::class],
autoMigrations = [
AutoMigration(from = 1, to = 2)
],
version = 2
)
abstract class UserDB : RoomDatabase()
即使我已经通过@ColumnInfo指定了默认值,但仍然得到相同错误:
// Compile Time Error:
// New NOT NULL column'height' added with no default value specified.
// Please specify the default value using @ColumnInfo.
@Entity(tableName = "user")
data class User(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
val id: Long = 0L,
@ColumnInfo(name = "name")
val name: String = "",
// specify default value by this way
@Column(name = "height", defaultValue = "0")
val height: Long = 0L
)
@Database(
entities = [User::class],
autoMigrations = [
AutoMigration(from = 1, to = 3)
],
// Since I have modify the structure of table,
// I increase the version.
version = 3
)
abstract class UserDB : RoomDatabase()
我的代码有什么问题,如何修复此错误?
我已经修改了<code>高度
从
@Column(name = "height", defaultValue = "0")
val height: Long = 0L
到
@ColumnInfo(name = "height", defaultValue = "0")
val height: Long = 0L
并执行上述步骤,但得到运行时异常
@ColumnInfo(name = “height”)
并通过编写手动迁移将数据库版本更新到版本2。然后运行新版本app;@ColumnInfo(name = “height”,defaultValue = “0”)
(如果我不指定默认值,房间编译器会告诉我,我必须通过在编译时抛出 Exception来指定默认值),并将版本从2增加到3,并指定autoMigrations到@Database
:@Database(
entities = [Worker::class],
autoMigrations = [AutoMigration(from = 1, to = 3)],
version = 3
)
abstract class UserDB : RoomDatabase()
然后在运行时执行这些代码并获得运行时异常:
val userDB = buildUserDB().openHelper.readableDatabase
Log.d(TAG, "columnNames=${workerDB.query("SELECT * FROM user").columnNames.toList()}")
// java.lang.IllegalStateException: A migration from 2 to 3 was required but not found.
// Please provide the necessary Migration path via RoomDatabase.Builder.addMigration(Migration ...)
// or allow for destructive migrations via one of the
// RoomDatabase.Builder.fallbackToDestructiveMigration* methods.
即使我已经通过@ColumnInfo指定了默认值,但仍然得到相同错误:
我相信(根据长版本)您的问题是您使用了< code>@Column(....而不是< code>@ColumnInfo(....。
所以改变
@Column(name = "height", defaultValue = "0")
val height: Long = 0L
到
@ColumnInfo(name = "height", defaultValue = "0")
val height: Long = 0L
使用两个运行来测试上述内容,一个在版本1,然后运行2(使用更正的@ColumnInfo),使用:-
class MainActivity : AppCompatActivity() {
lateinit var db: UserDB
lateinit var dao: UserDao
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
db = UserDB.getInstance(this)
dao = db.getUserDao()
dao.insert(User(name = "NAME001Version$DATABASE_VERSION"))
dao.insert(User(name = "NAME002Version$DATABASE_VERSION"))
dao.insert(User(name = "NAME003Version$DATABASE_VERSION"))
for (u in dao.getAllUsers()) {
Log.d("DBINFO","User ID = ${u.id} UserName is ${u.name} Version is ${DATABASE_VERSION}")
}
}
}
通过应用程序检查的数据库为:-
两次运行的日志:-
2022-05-24 19:32:57.784 D/DBINFO: User ID = 1 UserName is NAME001Version1 Version is 1
2022-05-24 19:32:57.784 D/DBINFO: User ID = 2 UserName is NAME002Version1 Version is 1
2022-05-24 19:32:57.784 D/DBINFO: User ID = 3 UserName is NAME003Version1 Version is 1
2022-05-24 19:38:41.963 D/DBINFO: User ID = 1 UserName is NAME001Version1 Version is 2
2022-05-24 19:38:41.963 D/DBINFO: User ID = 2 UserName is NAME002Version1 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 3 UserName is NAME003Version1 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 4 UserName is NAME001Version2 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 5 UserName is NAME002Version2 Version is 2
2022-05-24 19:38:41.964 D/DBINFO: User ID = 6 UserName is NAME003Version2 Version is 2
要复制此问题(必须为@Column添加基本注释),然后:-
我已经找到了这个问题的根本原因。
当房间编译器通过将1.json(模式json文件)与2.json比较生成migration_1_2
时,不会在生成migration_5_6
或其他迁移时引发此异常。
引发此异常的原因是1.json没有高度列,而2.json有非空高度列,但没有@ColumnInfo
中的默认值。
因为修改2.json(历史模式json文件)是危险的,所以我放弃了用自动迁移代替手动迁移的想法。
让我在Room Compiler展示一段代码来解释为什么会出现这个问题:
// SchemaDiffer.kt
class SchemaDiffer(...) {
...
private fun processAddedTableAndColumns(...) {
toColumns.values.forEach { toColumn ->
val match = fromColumns[toColumn.columnName]
if (match == null) {
if (toColumn.isNonNull && toColumn.defaultValue == null) {
// >>>>>>> ** HERE! ** >>>>>>>
// New NOT NULL column'height' added with no default value specified.
diffError(
newNotNullColumnMustHaveDefaultValue(toColumn.columnName)
)
}
}
}
}
}
这段代码告诉我,如果新列为非空,但在从旧数据库自动迁移到新数据库时没有指定默认值,那么Room编译器将抛出异常。
看看我的需求和我的代码:
和我的代码:
// column declaration
// a non null type long
// and has not specified default value on @ColumnInfo
@ColumnInfo(name = "height")
val height: Long = 0L
当房间编译器进程@ColumnInfo高度
字段上批注以生成migration_1_to_2
时,它会发现高度
字段非空值(通过 XType.nullability
)并且没有指定默认值(通过读取 @ColumnInfo.defalutValue
)。
然后,通过将 1.json 与 2.json 进行比较,房间编译器会发现高度
为 NEW 列。
有一个矛盾:高度
列是非空的,但它没有默认值!为了让开发人员知道这个问题,房间编译器选择抛出异常。
通过分析源代码,我们知道当房间编译器生成migration_1_to_2
时会引发异常,而不是在生成migration_5_to_6
或其他迁移时。所以即使我们指定了高度
的默认值,房间编译器仍然会抛出这个问题——当前版本是6,房间编译器会生成6.json,而不是2.json,默认规范不是写到2.json。
我认为修改历史架构json文件是危险的,所以我放弃了用自动迁移取代手动迁移的想法。
问题内容: 我想在下面的HTML片段中选择BONKERS。它的区别在于,它是单独存在的,而其所有兄弟姐妹都包含。是显而易见的选择,但由于文本节点而无法使用。我以为我知道这些东西,但这正驱使我疯狂。 我需要一个纯CSS解决方案(不能选择JS),并且无法控制源HTML。 ! 问题答案: 您可以按照这种方法。通过所需的CSS 设置元素的样式,然后重置可在样式中继承的CSS样式,即: CSS: 您可能不需
问题内容: 我尝试执行的几乎所有操作都收到“设备上没有剩余空间”错误。即使使用制表符自动完成命令! 但是当我做df -hi时得到: 在我看来,那里有无数的空间。df -i看起来也类似: 我在Amazon EC2 ubuntu 12.04实例上。 以下是错误弹出的一些示例: 但是服务器似乎正在运行,并且一切似乎都正常。到底是怎么回事? 问题答案: 可能是内存不足或其他地方有空间,它提示系统安装了溢出
问题内容: 我到目前为止发现的 所有@entity批注的类在编译期间进行处理,并且生成了Database的实现类。然后,在访问数据库之前,将调用此生成的类的validateMigration方法。这个validateMigration方法通过原始查询与现有的数据库架构进行验证 (请参见android.arch.persistence.room.util.TableInfo.java的L208) 现
我正在使用2.4.0-ALPHA01房间
Django v1.11.5 我试图安装GeoDjango来玩谷歌地图。 我为MAC安装了PostgreSQL应用程序,并安装了。我还使用自制软件安装GDAL。 要添加的已编辑设置.py: 但是,当我运行migrate时,我得到: 我创建用户使用: 完全错误: 运行迁移:Applying users.0011_location…Traceback(最后一次调用):在execute_from_com
我正在编写一个minecraft mod,当我在forge 1.8.9中运行它时,我得到了。然而,当我运行另一个mod时,这个mod可以工作。 我的mod的反编译类文件如下所示 而另一个看起来像 无论我如何构建我的mod,我的类文件永远不会像这样结束。如何让gradle混淆代码?