找不到字段的setter - 使用Kotlin和Room数据库

时间:2017-05-27 05:54:19

标签: android kotlin android-room

我正在与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注释适用于Room库。当我尝试构建时,它失败并出现错误:

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类,它就可以工作。任何帮助表示赞赏!

15 个答案:

答案 0 :(得分:117)

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

尝试使用val切换var。 您可能还需要初始化字段。

@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 = ""
)

答案 1 :(得分:19)

嘿,我不知道每个人是否都知道,但你不能拥有从is开始进入Room的专栏。 例如,你不能这样

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

答案 2 :(得分:4)

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

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

之前 var isFavorite: Int? = 0, 换工作后罚款 var favorite: Int? = 0, 谢谢

答案 3 :(得分:3)

根据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

enter image description here

然后我将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

答案 4 :(得分:3)

我发现造成此编译错误的另一个原因可能是由于在实体数据类的字段上使用了会议室的const inputs = `This is right. This isn't right. "I said ok."`.split('\n'); for (const input of inputs) { console.log(input.match(/\w[\w']*| +|[.,"]/g)); }注释:

@Ignore

使用@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 ) 批注时似乎也会发生相同的错误。

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

2.2.2

希望对某人有帮助!

答案 5 :(得分:2)

在Java中出现此错误。您必须在构造函数中传递该字段并使用构造函数参数对其进行初始化,或者为其创建一个setter。

示例:

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

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

答案 6 :(得分:2)

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

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

  

错误修复

     
      
  • Room现在将正确使用Kotlin的主要构造函数   数据类,无需将字段声明为vars。   b/105769985
  •   

答案 7 :(得分:2)

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

var workerId: Long? = null

{{1}}

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

答案 8 :(得分:1)

另一个原因可能是该领域的命名。如果您使用任何预定义的关键字,您将得到相同的错误。 例如,您无法命名您的列" is_active"。

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

答案 9 :(得分:1)

如果有人花了数小时在网上搜索为什么应该起作用,那么在2019年有人遇到这个线程,这只是一个更新。

如果您使用的是AndroidX版本(val,则使用androidx.room:room-<any>:2.*可以正常工作,但是使用旧的android.arch.persistence.room:<any>:1.1.1时却不能使用2.*没有在后一个回购中发布。

编辑:错别字

答案 10 :(得分:1)

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

  1. 您应该更新到AndroidX会议室current version
  2. 检查相关的issue here,将其标记为无法修复
  3. 现在他们已经发布了与version 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是一个不错的解决方法,但是我更希望实体类在外部调用时是不可变的

答案 11 :(得分:1)

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

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

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

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

答案 12 :(得分:1)

如果数据类构造函数中有@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上的marianperca上:https://github.com/android/architecture-components-samples/issues/421#issuecomment-442763610

答案 13 :(得分:0)

您现在可以从resolver = dns.resolver.Resolver() resolver.timeout = 1 resolver.lifetime = 1 return float("{0:.3f}".format(dns.resolver.query(url).response.time*1000)) 开始字段,但是is旁边没有数字,例如:is,您必须重命名为is2FooSelected

答案 14 :(得分: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
)