90

我正在与 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
)

和注释用于 Room 库@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 类,它就可以工作。任何帮助表示赞赏!

4

16 回答 16

202

由于您的字段标有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 库的不变性根本不起作用,并且在制造悲伤的开发人员噪音的同时,不幸val的是,您必须将其切换var

于 2017-05-27T06:10:53.333 回答
49

嘿我不知道大家是否知道,但你不能有从isinto开始的专栏Room。例如你不能有这样的

   @Entity(tableName = "user")
   data class User (
        @PrimaryKey var id: Long? = null,
        var userName: String = "",
        var isConnectedToFB: Boolean = false,
)
于 2018-01-02T12:50:46.273 回答
8

room db 库 java 代码生成存在问题。

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

var isFavorite: Int? = 0, 更改工作正常 之前var favorite: Int? = 0, 谢谢

于 2018-08-10T12:22:41.473 回答
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,你会得到一个警告(over idvariable)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
于 2018-08-22T06:59:25.617 回答
7

如果@Ignore数据类构造函数中有字段,则需要将其移动到类主体,如下所示:

@Entity(primaryKeys = ["id"])
data class User(
        @field:SerializedName("id")
        val id: Int,

        @field:SerializedName("name")
        val name: String,
    
        @field:SerializedName("age")
        val age: Int
) {
    @Ignore
    val testme: String?
}

所有荣誉都转到GitHub 上的marianpercahttps ://github.com/android/architecture-components-samples/issues/421#issuecomment-442763610

于 2020-09-17T10:58:40.777 回答
6

Java中有这个错误。

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

尝试重命名该列。

另一种解决方案:

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

例子:

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

public void setName(String name) {
    this.name = name;
}
于 2017-12-23T17:54:13.660 回答
5

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

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

添加一个默认的 set() 函数来消除

fun setIsHandicapLeague(flag:String) {
    isHandicapLeague = flag
}
于 2020-07-16T11:32:59.113 回答
4

我发现此编译错误的另一个原因可能是由于在@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"
   ...
}

希望对某人有所帮助!

于 2020-02-19T02:42:38.600 回答
4

这是一个错误,已在 Room 中修复2.1.0-alpha01

https://developer.android.com/jetpack/docs/release-notes#october_8_2018

Bug修复

  • Room 现在将在数据类中正确使用 Kotlin 的主要构造函数,避免将字段声明为 var。 b/105769985
于 2018-10-11T22:32:32.783 回答
3

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

var id: Long? = null

var workerId: Long? = null

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

于 2020-12-11T23:46:09.750 回答
2

只需使变量可变,对于 Kotlin 更改为,或者对于 Java 将私有更改为val公共var

于 2021-08-22T14:33:03.580 回答
2

另一个原因可能是字段的命名。如果您使用任何预定义的关键字,您将得到相同的错误。例如,您不能将列命名为“is_active”。

参考:http ://www.sqlite.org/lang_keywords.html

于 2017-11-21T15:15:24.973 回答
1

如果有人在 2019 年遇到此线程,则只是一个更新,在花费数小时在线挖掘为什么这应该有效之后,但事实并非如此。

如果您使用的是valAndroidX 版本(androidx.room:room-<any>:2.*android.arch.persistence.room:<any>:1.1.12.*

编辑:错别字

于 2019-03-06T15:16:15.400 回答
1

如果您希望val实体可用的不变性,这是可能的。

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

以前,上面的代码片段会抛出Cannot find setter for field. 更改为var是一个很好的解决方法,但我更喜欢实体类在外部调用中是不可变的

于 2019-05-14T09:15:12.973 回答
0

您现在可以开始您的字段,is但您不能在is类似 :旁边有一个数字is2FooSelected,您必须重命名为isTwoFooSelected.

于 2019-10-04T10:33:52.453 回答
-2

Just use var instead of val and if you are using private keyword, make it public.

@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
)
于 2020-02-20T13:15:01.323 回答