找不到字段的设置器-将Kotlin与Room数据库一起使用


74

我正在与Room持久性库集成。我在Kotlin中有一个数据类,例如:

@Entity(tableName = "story")
data class Story (
        @PrimaryKey val id: Long,
        val by: String,
        val descendants: Int,
        val score: Int,
        val time: Long,
        val title: String,
        val type: String,
        val url: String
)

@Entity@PrimaryKey注解是为客房库。当我尝试构建时,它因错误而失败:

Error:Cannot find setter for field.
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

我也尝试提供默认的构造函数:

@Entity(tableName = "story")
data class Story (
        @PrimaryKey val id: Long,
        val by: String,
        val descendants: Int,
        val score: Int,
        val time: Long,
        val title: String,
        val type: String,
        val url: String
) {
    constructor() : this(0, "", 0, 0, 0, "", "", "")
}

但这并不能正常工作。需要注意的一点是,如果我将此Kotlin类转换为带有getter和setter的Java类,它将起作用。任何帮助表示赞赏!


3
在google的示例中的github.com/googlesamples/android-architecture-components/blob/…中,不可变的属性可以正常工作。有人可以分析原因吗?可能是错误吗?
塞缪尔·罗伯

Answers:


175

由于您的字段标有val,因此实际上是最终字段,没有设置者字段。

尝试切换出valvar。您可能还需要初始化字段。

@Entity(tableName = "story")
data class Story (
        @PrimaryKey var id: Long? = null,
        var by: String = "",
        var descendants: Int = 0,
        var score: Int = 0,
        var time: Long = 0L,
        var title: String = "",
        var type: String = "",
        var url: String = ""
)

编辑

上面的解决方案是将Kotlin与其他Java库(例如Hibernate)结合使用时针对Kotlin中此错误的一般解决方案,我也看到了这一点。如果您想保持Room的不变性,请参阅一些其他答案,这些答案可能更适合您的情况。

在某些情况下不变性与Java库是在所有根本不工作,同时使开发者悲伤的声音,你可以切换valvar不幸。


1
嘿,我觉得这很奇怪,可以看看吗?stackoverflow.com/q/47323883/4620609
塞缪尔·罗伯

感谢您的指针,这个问题造成约2小时,我.....我用“私人变种”,它被扔的错误,没有任何线索
anoop4real

7
答案是“不要使用Room,它会迫使您编写错误的代码”,对吗?
Miha_x64 '18

4
请注意,数据类中的var使用会导致有效的不变性损失。
yaroslav

此解决方案对我有用,但对其他遇到相同问题的人也适用。我还必须删除我的私人可见性修改器。
令牌生成器'18

38

嘿,我不知道每个人是否都知道,但是您不能拥有从isin开始的列Room。例如你不能像这样

   @Entity(tableName = "user")
   data class User (
        @PrimaryKey var id: Long? = null,
        var userName: String = "",
        var isConnectedToFB: Boolean = false,
)

2
就我而言,“ is”前缀不适用于字段名称。但是“ is”前缀适用于布尔类型字段。
David Guo

@AlexAndro我在kotlin本身中给出了示例,您能解释一下什么不起作用吗?
AJay

@AJay我的意思是我同意你的看法,因为kotlin你不能有这样的领域。(投票)无论如何,在java我注意到是允许的。
AlexAndro

1
在Java中也会发生同样的事情。您不能使用“ mIs___”或“ is____”。它将导致相同的错误。匈牙利表示法不会挽救您。
d4c0d312 '18

1
在科特林工作
Naimish Vinchhi,

7

根据https://stackoverflow.com/a/46753804/2914140,如果您具有自动生成的主键,则应这样写:

@Entity(tableName = "story")
data class Story (
        val by: String,
        val descendants: Int,
        val score: Int,
        val time: Long,
        val title: String,
        val type: String,
        val url: String
)  {
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
}

请注意,@PrimaryKey它写在类主体内部并包含修饰符var

如果以后要使用不同的参数更新数据库中的行,请使用以下几行:

val newStory = story.copy(by = "new author", title = "new title") // Cannot use "id" in object cloning
newStory.id = story.id
dao.update(newStory)

更新

我仍然不使用AndroidX,并且Room为“ android.arch.persistence.room:runtime:1.1.1”。

您可以从扩展此类Serializable。但是,如果您要从扩展它Parcelable,则会收到警告(在id变量上方)Property would not be serialized inro a 'Parcel'. Add '@IgnoredOnParcel' annotation to remove this warning::

在此处输入图片说明

然后我将一个id从正文移到了构造函数。在Kotlin中,我@Parcelize用来创建Parcelable类:

@Parcelize
@Entity(tableName = "story")
data class Story (
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,

    val by: String,
    val descendants: Int,
    val score: Int,
    val time: Long,
    val title: String,
    val type: String,
    val url: String
) : Parcelable

6

房间数据库库Java代码生成中存在问题。

我正在使用可选字段isFavorite。它给了我同样的错误,然后我将字段名称更改为favorite然后编译。

var isFavorite: Int? = 0, 改变工作之前之前 很好 var favorite: Int? = 0, 谢谢


更改您的数据类型。我在数据库中有一个名为isFavourite的字段,我将字段类型更改为boolean,现在对我有用。@ColumnInfo(name =“ is_favourite”)var isFavourite:布尔值= false
Gevaria Purva

5

在Java中发生此错误。

您不能有以Java开头isis_以Java开头的列。

尝试重命名该列。

另一个解决方案:

您要么必须在构造函数中传递该字段,然后使用构造函数参数对其进行初始化,要么为其创建一个setter。

例:

public MyEntity(String name, ...) {
   this.name = name;
   ...
}

public void setName(String name) {
    this.name = name;
}


3

我发现导致此编译错误的另一个原因可能是由于@Ignore在实体数据类的字段上使用了Room的注释:

@Entity(tableName = "foo")
data class Foo(

    // Okay
    @PrimaryKey
    val id: String,

    // Okay
    val bar: String,

    // Annotation causes compilation error, all fields of data class report
    // the "Cannot find setter for field" error when Ignore is present
    @Ignore
    val causeserror: String
)

使用@Transient注释时,似乎也会发生相同的错误。

我已经注意到使用2.2.2Room版本的此问题:

// build.gradle file
dependencies {
   ...
   kapt "androidx.room:room-compiler:2.2.2"
   ...
}

希望能对某人有所帮助!


您找到任何解决方案吗?卡在相同的情况下。谢谢
Abhishek Batra

就我而言,我需要@Ignore从实体类的字段中删除。也许您已将@Ignore一个或多个实体类的字段包括在内?
达克里丹尼

显然,Room库无法实例化数据类的对象,因为数据类必须具有数据库中不存在的字段(由于@Ignore注释)。
soshial


2

您可以尝试将id变量重命名为另一个名称。它为我工作;

var id: Long? = null

var workerId: Long? = null

如果您必须命名为id并且正在使用改造,则可能需要添加SerializedName(“ id”)



1

在花了几个小时在线研究为什么应该工作之后,如果有人在2019年遇到这个问题,这只是一个更新,但事实并非如此。

val如果您使用的是AndroidX版本(androidx.room:room-<any>:2.*),则using可以按预期工作,但使用旧android.arch.persistence.room:<any>:1.1.1版本2.*时不会使用,并且似乎未在此后一个版本中发布该版本。

编辑:错别字


是的,AndroidX将取代支持库,因此Room永远不会是旧版的2.0 android.arch.persistence.room
CoolMind

感谢您的信息
Jibbo

2
在我的情况下,即使使用androidx和最新的Room,val在Int和Long中也不起作用
yaroslav

1

如果您希望val实体具有不可变性,则可以。

  1. 您应该更新为AndroidX room当前版本
  2. 在此处检查相关问题其标记为“无法修复”
  3. 现在他们已经发布了与2.0.0-beta01版本相关的修复程序
  4. 现在,您可以将不可变valdefault value例如:
@Entity("tbl_abc")
data class Abc(
    @PrimaryKey
    val id: Int = 0, 
    val isFavourite: Boolean = false
)

以前,以上代码段将引发的错误Cannot find setter for field。更改为var一个不错的解决方法,但是我更希望实体类不能从外部调用中更改


1

如果您的列以Is开头,则会引发此错误:

@ColumnInfo(name = "IsHandicapLeague")
    @NonNull
    var isHandicapLeague: String = "Y"

添加默认的set()函数以消除

fun setIsHandicapLeague(flag:String) {
    isHandicapLeague = flag
}

0

您现在可以以开头的字段,is但旁边不能包含数字isis2FooSelected,您必须重命名为isTwoFooSelected


0

只需使用var而不是val,如果您使用的是private关键字,请将其设为公开。

@Entity(tableName = "story")
data class Story (
        @PrimaryKey val id: Long,
        var by: String,
        var descendants: Int,
        var score: Int,
        var time: Long,
        var title: String,
        var type: String,
        var url: String
)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.