Setter für Feld kann nicht gefunden werden - Kotlin mit Raumdatenbank wird verwendet


74

Ich bin in die Room Persistence Library integriert. Ich habe eine Datenklasse in Kotlin wie:

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

Die @Entityund @PrimaryKeyAnmerkungen gelten für die Raumbibliothek. Wenn ich versuche zu bauen, schlägt es mit Fehler fehl:

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

Ich habe auch versucht, einen Standardkonstruktor bereitzustellen:

@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, "", "", "")
}

Das funktioniert aber nicht so gut. Zu beachten ist, dass es funktioniert, wenn ich diese Kotlin-Klasse in eine Java-Klasse mit Getter und Setter konvertiere. Jede Hilfe wird geschätzt!


3
In github.com/googlesamples/android-architecture-components/blob/… aus dem Beispiel von Google funktionieren unveränderliche Eigenschaften problemlos. Kann jemand die Ursache analysieren? Könnte es ein Fehler sein?
Samuel Robert

Antworten:


175

Da Ihre Felder mit markiert sind val, sind sie effektiv endgültig und haben keine Setterfelder.

Versuchen Sie das valmit auszutauschen var. Möglicherweise müssen Sie auch die Felder initialisieren.

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

BEARBEITEN

Die obige Lösung ist eine allgemeine Lösung für diesen Fehler in Kotlin, wenn Kotlin mit anderen Java-Bibliotheken wie Hibernate verwendet wird, wo ich dies ebenfalls gesehen habe. Wenn Sie die Unveränderlichkeit von Room beibehalten möchten, lesen Sie einige der anderen Antworten, die möglicherweise spezifischer für Ihren Fall sind.

In einigen Fällen Unveränderlichkeit mit Java - Bibliotheken ist einfach nicht funktioniert und während traurig Entwickler Geräusche, haben Sie , dass wechseln valfür einen varleider.


1
Hey, ich dachte mir etwas Seltsames. Könntest du es dir ansehen? stackoverflow.com/q/47323883/4620609
Samuel Robert

Vielen Dank für den Hinweis, dieses Problem tötete ungefähr 2 Stunden für mich ..... Ich habe "private var" verwendet und es warf Fehler, hatte keine Ahnung
anoop4real

7
Die Antwort bedeutet "benutze keinen Raum, es zwingt dich, schlechten Code zu schreiben", oder?
Miha_x64

4
Bitte beachten Sie, dass die Verwendung von Variablen in Datenklassen zu einem effektiven Verlust der Unveränderlichkeit führt.
Jaroslaw

Diese Lösung funktionierte für mich, aber für alle anderen, die das gleiche Problem hatten. Ich musste auch meinen privaten Sichtbarkeitsmodifikator entfernen.
Der Tokenizer

38

Hey, ich weiß nicht, ob jeder weiß oder nicht, aber Sie können keine Spalte haben, die von isin beginnt Room. Zum Beispiel kann man so etwas nicht haben

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

2
In meinem Fall funktioniert das Präfix "is" nicht für den Feldnamen. Das Präfix "is" funktioniert jedoch mit dem Feld vom Typ Boolean.
David Guo

@AlexAndro Ich habe ein Beispiel in Kotlin selbst gegeben. Kannst du bitte erklären, was nicht funktioniert?
AJay

@AJay Ich meine, ich stimme dir zu, dass kotlindu solche Felder nicht haben kannst. (nach oben abstimmen) Jedenfalls ist javamir aufgefallen, dass es erlaubt ist.
AlexAndro

1
Das gleiche passiert in Java. Sie können "mIs___" oder "is____" nicht verwenden. Es wird den gleichen Fehler verursachen. Die ungarische Notation wird Sie nicht retten.
d4c0d312

1
Arbeiten in Kotlin
Naimish Vinchhi

7

Laut https://stackoverflow.com/a/46753804/2914140 sollten Sie Folgendes schreiben, wenn Sie einen automatisch generierten Primärschlüssel haben:

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

Beachten Sie, dass dies @PrimaryKeyim Klassenkörper geschrieben ist und den Modifikator enthält var.

Wenn Sie später eine Zeile in einer Datenbank mit anderen Parametern aktualisieren möchten, verwenden Sie die folgenden Zeilen:

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

AKTUALISIEREN

Ich benutze AndroidX immer noch nicht und Room ist 'android.arch.persistence.room:runtime:1.1.1'.

Sie können diese Klasse von erweitern Serializable. Wenn Sie es jedoch erweitern möchten Parcelable, erhalten Sie eine Warnung (über idVariable) Property would not be serialized inro a 'Parcel'. Add '@IgnoredOnParcel' annotation to remove this warning::

Geben Sie hier die Bildbeschreibung ein

Dann habe ich eine idvom Körper zum Konstruktor verschoben . In Kotlin @Parcelizeerstelle ich ParcelableKlassen:

@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

Es gibt ein Problem bei der Generierung von Java-Code in der Room-DB-Bibliothek.

Ich habe ein optionales Feld verwendet isFavorite. Es gibt mir den gleichen Fehler, dann ändere ich meinen Feldnamen in favoritedann kompiliert.

vorher var isFavorite: Int? = 0, nach dem wechseln funktioniert gut var favorite: Int? = 0, Danke


Ändern Sie Ihren Datentyp. Ich habe das gleiche Feld mit dem Namen isFavourite in meiner Datenbank. Ich habe meinen Feldtyp in boolean geändert und jetzt funktioniert es für mich. @ ColumnInfo (name = "is_favourite") var isFavourite: Boolean = false
Gevaria Purva

5

Hatte diesen Fehler in Java.

Sie können keine Spalte haben, die mit isoder is_in Java beginnt .

Versuchen Sie, die Spalte umzubenennen.

Eine andere Lösung:

Sie müssen entweder das Feld im Konstruktor übergeben und mit dem Konstruktorargument initialisieren oder einen Setter dafür erstellen.

Beispiel:

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

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


3

Ich habe festgestellt, dass eine weitere Ursache für diesen Kompilierungsfehler in der Verwendung der @IgnoreAnnotation des Raums für Felder Ihrer Entitätsdatenklasse liegen kann:

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

Der gleiche Fehler scheint auch bei der Verwendung der @TransientAnnotation aufzutreten.

Ich habe dieses Problem bei der Verwendung 2.2.2der Room- Version festgestellt :

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

Hoffe das hilft jemandem!


Haben Sie eine Lösung dafür gefunden? Mit dem gleichen Fall stecken. Vielen Dank
Abhishek Batra

In meinem Fall musste ich @Ignoreaus Feldern meiner Entitätsklasse entfernen . Vielleicht haben Sie @IgnoreFelder in einer oder mehreren Ihrer Entitätsklassen eingefügt?
Dacre Denny

Offensichtlich kann die Raumbibliothek ein Objekt Ihrer Datenklasse nicht instanziieren, da die Datenklasse ein Feld haben muss, das (aufgrund der @IgnoreAnmerkung) nicht in der Datenbank vorhanden ist .
Soshial


2

Sie können versuchen, die ID-Variable in einen anderen Namen umzubenennen. Es hat bei mir funktioniert;

var id: Long? = null

zu

var workerId: Long? = null

Wenn Sie einen Namen als ID angeben müssen und eine Nachrüstung verwenden, müssen Sie möglicherweise SerializedName ("ID") hinzufügen.


1

Eine weitere Ursache hierfür kann die Benennung des Feldes sein. Wenn Sie eines der vordefinierten Schlüsselwörter verwenden, wird der gleiche Fehler angezeigt. Beispielsweise können Sie Ihre Spalte nicht "is_active" nennen.

Referenz: http://www.sqlite.org/lang_keywords.html


1

Nur ein Update, wenn jemand 2019 auf diesen Thread stößt, nachdem er stundenlang online darüber nachgedacht hat, warum dies funktionieren sollte, aber es funktioniert nicht.

Die Verwendung valfunktioniert wie erwartet, wenn Sie die AndroidX-Version ( androidx.room:room-<any>:2.*) verwenden, jedoch nicht, wenn Sie die alte verwenden, android.arch.persistence.room:<any>:1.1.1und es scheint, dass die Version 2.*für dieses letztere Repo nicht veröffentlicht wurde.

Bearbeiten: Tippfehler


Ja, AndroidX wird Support-Bibliotheken ersetzen, sodass Room niemals älter als 2.0 sein wird android.arch.persistence.room.
CoolMind

Danke für die Info
Jibbo

2
Val funktioniert in meinem Fall nicht mit Int und Long, auch nicht mit Androidx und dem neuesten Room
Jaroslaw

1

Wenn Sie möchten, dass die valUnveränderlichkeit für Ihr Unternehmen verfügbar ist, ist dies möglich.

  1. Sie sollten auf die aktuelle Version des AndroidX-Raums aktualisieren .
  2. Suchen Sie hier nach dem entsprechenden Problem, das als Nicht behoben markiert ist
  3. Jetzt haben sie einen Fix für das Problem mit Version 2.0.0-beta01 veröffentlicht
  4. Jetzt können Sie unveränderlich verwenden valmit default valuezB:
@Entity("tbl_abc")
data class Abc(
    @PrimaryKey
    val id: Int = 0, 
    val isFavourite: Boolean = false
)

Zuvor wird das obige Snippet einen Fehler von auslösen Cannot find setter for field. Das Wechseln in varist eine großartige Problemumgehung, aber ich bevorzuge, dass die Entitätsklasse von einem externen Aufruf unveränderlich ist


1

Dieser Fehler wird ausgelöst, wenn Ihre Spalte mit Is beginnt:

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

Fügen Sie eine Standardfunktion set () hinzu, um sie zu entfernen

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

0

Sie können Ihr Feld jetzt mit beginnen, isaber Sie können keine Nummer neben der isgleichen haben: is2FooSelectedSie müssen umbenennen in isTwoFooSelected.


0

Verwenden Sie einfach var anstelle von val und machen Sie es öffentlich, wenn Sie ein privates Schlüsselwort verwenden.

@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
)
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.