【问题标题】:Room Database error with Kotlin Data ClassKotlin 数据类的房间数据库错误
【发布时间】:2018-03-28 04:55:20
【问题描述】:

我已经开始使用 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.

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

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

更新:从我的项目中添加更多相关代码 sn-ps。

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.

【问题讨论】:

    标签: android kotlin android-room


    【解决方案1】:

    您的问题是,如果您有可为空的值,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 类是否具有有效的类型转换器。我很久以前写过that issue

    在对上面的内容重新编码后,通过添加这样的 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"
    

    我很久以前写过an issue

    【讨论】:

    • 我在 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). 你的建议和我发现的是,这些构造函数都存在,包括具有与字段匹配的所有参数的构造函数.
    • 我已将您的课程添加到我的项目中,并且可以完美运行。即使在清理项目、使缓存无效等之后。您能否发布您的 Gradle 文件
    • 我已经发布了相关的 Gradle sn-p,以及实现中的一些其他文件。
    • 请发布类 UserPermissions。我已经完全重新编码了您上面的内容,并且通过添加一个仅包含“permissionID”作为参数的 UserPermissions 类,它编译得很好。
    • 在帖子中添加了完整的 UserPermissions 类。很奇怪,你可以毫无问题地使用所有东西。
    【解决方案2】:

    这个问题极难调试,也更难重现,但我发现了这个问题。我使用的是@Embedded 对象,但输入的结果实际上是该对象的List。这给自动嵌入任务带来了麻烦,并且没有可以为其编写完美的转换器。

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

    我必须用 @Ignore 注释它,相反,我会将此列表的结果保存到它自己的表中,现在是新表 range_choices

    【讨论】:

    • 这行得通.. +1。事实上,对于那些不想使用忽略的人,您可以简单地指定您的类型转换器,但不要将 @Embedded 包含在对象列表中
    【解决方案3】:

    您的主键应如下所示,使用Annotation Use-site Targets

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

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

    【讨论】:

    • 你确定你了解基于 kotlin 的注解的使用吗? ;-)
    • @EmanuelS 如果您指出使用基于 kotlin 的注释的确切问题,您会很高兴。我也附上了官方文件。
    【解决方案4】:

    尽量避免使用可为空的值,并让一切都具有某种默认值。这是解决此问题的最简单方法。

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

    【讨论】:

      猜你喜欢
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多