Невозможно найти сеттер для поля - используя базу данных Kotlin с комнатой

Я интегрируюсь с библиотекой Persistence. У меня есть класс данных в 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 в класс Java с помощью геттеров и сеттеров. Любая помощь приветствуется!

Ответ 1

Поскольку ваши поля отмечены 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 = ""
)

Ответ 2

Эй, я не знаю, знают ли все или нет, но у вас не может быть столбца, начинающегося с is в Room. Например, вы не можете иметь это

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

Ответ 3

Существует проблема в генерации Java-библиотеки библиотеки db.

Я использовал необязательное поле isFavorite. Это дает мне ту же ошибку, после чего я изменяю имя поля на favorite затем компилируемое.

перед var isFavorite: Int? = 0, var isFavorite: Int? = 0, после изменения отлично работает var favorite: Int? = 0, var favorite: Int? = 0, спасибо

Ответ 4

Это ошибка и исправлена в комнате 2.1.0-alpha01

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

Исправление ошибок

  • Теперь Room будет правильно использовать основной конструктор Kotlins в классах данных, избегая необходимости объявлять поля как переменные. б /105769985

Ответ 5

Согласно fooobar.com/questions/252524/... если у вас есть автоматически сгенерированный первичный ключ, вы должны написать так:

@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 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

Ответ 6

Была эта ошибка в Java.

Вы не можете иметь столбец, начинающийся с is или is_ в Java.

Попробуйте переименовать столбец.

Другое решение:

Вы должны либо передать поле в конструктор и инициализировать его аргументом конструктора, либо создать для него установщик.

Пример:

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

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

Ответ 7

Другой причиной этого может быть именование поля. Если вы используете какой-либо из предопределенных ключевых слов, вы получите ту же ошибку. Например, вы не можете назвать свой столбец "is_active".

Ссылка: http://www.sqlite.org/lang_keywords.html

Ответ 8

Просто обновление, если кто-то сталкивается с этой темой в 2019 году, потратив часы на то, чтобы выяснить, почему это должно работать, но это не так.

Использование val работает должным образом, если вы используете версию androidx.room:room-<any>:2.* (androidx.room:room-<any>:2.*), но не работает при использовании старого android.arch.persistence.room:<any>:1.1.1 и кажется, что версия 2.* не была выпущена в этом последнем репо.

Редактировать: опечатки

Ответ 9

Если вы хотите, чтобы для вашей сущности была доступна неизменность val, это возможно.

  1. Вам следует обновить текущую версию комнаты AndroidX.
  2. Проверьте наличие связанной проблемы здесь, она помечена как не будет устранена
  3. Теперь они выпустили исправление, связанное с проблемой с версией 2.0.0-бета01
  4. Теперь вы можете использовать неизменный val со default value например:
@Entity("tbl_abc")
data class Abc(
    @PrimaryKey
    val id: Int = 0, 
    val isFavourite: Boolean = false
)

Ранее приведенный фрагмент кода выдавал ошибку Cannot find setter for field. Переход на var - отличный обходной путь, но я предпочитаю, чтобы класс сущности был неизменным при внешнем вызове.

Ответ 10

Теперь вы можете начать свое поле с is, но у вас не может быть номера рядом с is, например: is2FooSelected, вы должны переименовать в isTwoFooSelected.