Kotlin数据类的房间数据库错误

我一直在使用Room,而且遇到阻塞问题。 我已经完成并修复了Room库中的所有编译时检查,但是现在遇到以下错误:

Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). 

这在编译时出现了两次,没有证据表明这是从哪个类来的,但是我能够弄清楚(通过从数据库中删除类)这是其中的一个文件。 我假设它与主键是一个字符串,而不是一个Int(这是使用此类的两个类之一)有关,但文档中没有任何内容表明问题是什么,实际上文档显示该字符串是有效的主键。

 @Entity(tableName = "inspections") data class Inspection( @SerializedName("id") var id: Int = 0, ... // Rest of code left off for brevity, found to not be related to the issue. 

我已经尝试了一些事情来尝试解决这个问题。

  • 删除这个类的数据属性,使其成为一个普通的POKO
  • 从默认构造函数中删除变量,并将其放置到类中
  • 从空的构造函数中删除Ignore(注意,这会导致一个不同的问题, Room cannot pick a constructor since multiple constructors are suitable – 默认构造函数的Ignore标注可以解决这个问题。)这是最困惑我的部分这说“多个构造函数是有效的”,保持它说“没有构造函数是有效的”。

更新:从我的项目中添加更多相关的代码片段。

的build.gradle

 apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' ..... implementation 'android.arch.persistence.room:runtime:1.0.0-alpha9-1' implementation 'android.arch.persistence.room:rxjava2:1.0.0-alpha9-1' kapt 'android.arch.persistence.room:compiler:1.0.0-alpha9-1' 

数据库类

 @Database(entities = arrayOf(Account::class, Category::class, Inspection::class, InspectionForm::class, InspectionFormItem::class, InspectionFormsStructure::class, InspectionItemPhoto::class, InspectionItem::class, LineItem::class, LocalPhoto::class, Rating::class, Structure::class, SupervisoryZone::class, Upload::class, User::class), version = 16) @TypeConverters(Converters::class) abstract class OrangeDatabase : RoomDatabase() { abstract fun inspectionDao(): InspectionDao abstract fun localDao(): LocalDao abstract fun ratingsDao(): RatingsDao abstract fun structureZoneDao(): StructureZoneDao abstract fun userAccountDao(): UserAccountDao } 

转换器

 class Converters { @TypeConverter fun fromTimestamp(value: Long?): Date? { return if (value == null) Date() else Date(value) } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time ?: 0 } @TypeConverter fun fromStringToArray(value: String?): Array<String>? { return value?.split(",")?.toTypedArray() ?: arrayOf() } @TypeConverter fun stringToStringArray(strings: Array<String>?): String? { return strings?.joinToString(",") ?: "" } } 

另一个数据类

 @Entity(tableName = "users") data class User( @PrimaryKey @SerializedName("id") var id: Int = 0, ... // Rest of code left off for brevity, found to not be related to the issue. 

UserPermissions类:

 data class UserPermissions( @SerializedName("id") var pid: Int = 0, ... // Rest of code left off for brevity, found to not be related to the issue. 

在你的情况的问题是,如果你有可为空的值Kotlin会为每个可能的构造函数生成几个构造函数。

这意味着你必须定义一个默认构造函数,并用默认值填充它。

如果你想要另一个应该被忽略的,你应该确保使用父构造函数的所有这些参数。

例:

 @Entity(tableName = "inspections") data class Inspection( @SerializedName("id") var id: Int = 0, @PrimaryKey @SerializedName("guid") var guid: String = "", @SerializedName("score") var score: Double = 0.0, @SerializedName("notification_sent_at") var notificationSentAt: Date = Date(), var wasUploaded: Boolean = false) { @Ignore constructor() : this(0, "", 0.0, Date(), false) } 

在这种情况下,只有两个构造函数将在“引擎盖下”生成。 如果你有可以为空的值,你将拥有所有可能的构造函数。

例:

 data class Test(var id: Int = 0, var testString: String? = null, var testBool : Boolean? = null) { constructor(0) } 

生成

 constructor(var id:Int) constructor() : this(0) constructor(var id:Int, var testString: String) constructor(var id:Int, var testBool: Boolean) constructor(var id:Int, var testString: String, var testBool : Boolean) // .. and so on 

既然你正在寻找官方文档,你可能想看看Overloads Generation 。

经过测试你的课程完美无瑕,我发现在另一篇文章中,你必须检查你是否在你的Gradle中使用了apply plugin: 'kotlin-kapt'

仔细检查你的Date类是否有有效的类型转换器。 我之前写过这个问题 。

重新编码你的东西上面后,它工作得很好,通过添加一个UserPermissions类如下:

 data class UserPermissions(var permissionid: String) 

编辑:使用你的UserPermission类后,一切工作得很好。 请小心,如果您使用正确的导入(util.Date而不是sql.Date为例)。

另一个问题是,你使用一个古老的非常错误的房间库。

目前的版本(当写这个)是

 implementation "android.arch.persistence.room:runtime:1.0.0-beta2" kapt "android.arch.persistence.room:compiler:1.0.0-beta2" implementation "android.arch.persistence.room:rxjava2:1.0.0-beta2" 

我很久以前写了一个问题

尽量避免使用可为空的值,并使所有的东西都有某种默认值。 这是解决这个问题最简单的方法。

如果你真的想使用它们,那么你可以创建一个构造函数,包含所有的构造函数。

您的主键应该像下面使用注释使用站点目标一样

 @field:PrimaryKey @field:SerializedName("guid") var guid: String = "" 

 @field:PrimaryKey @field:SerializedName("id") var id: Int = 0 

这个问题是非常难以调试和更难以重现,但我发现这个问题。 我正在使用一个@Embedded对象,但是结果是实际上是该对象的List 。 这给自动嵌入任务带来了麻烦,并没有一个完美的转换器可以写出来。

 @SerializedName("range_choices") @Embedded var rangeChoices: List<RangeChoice>? = null, 

我不得不使用@Ignore注释,而是将这个列表的结果保存到它自己的表中,现在是新表range_choices