Raumpersistenz: Fehler: Entitäten und Pojos müssen über einen verwendbaren öffentlichen Konstruktor verfügen

74

Ich konvertiere ein Projekt in Kotlin und versuche, mein Modell (das auch meine Entität ist) zu einer Datenklasse zu machen, die ich mit Moshi zum Konvertieren der JSON-Antworten von der API verwenden möchte

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String,
    var overview: String,
    var poster_path: String,
    var backdrop_path: String,
    var release_date: String,
    var vote_average: Double,
    var isFavorite: Int
)

Ich kann die App wegen des folgenden Fehlers nicht erstellen

Entitäten und Pojos müssen einen verwendbaren öffentlichen Konstruktor haben. Sie können einen leeren Konstruktor oder einen Konstruktor haben, dessen Parameter mit den Feldern übereinstimmen (nach Name und Typ). Setter für Feld kann nicht gefunden werden.

Die Beispiele, die ich gefunden habe, sind nicht weit davon entfernt

Ideen, wie man es löst?

Leonardo Deleon
quelle
1
Welche Kotlin-Version ist das? Können Sie auch die vollständige Fehlermeldung ausdrucken? Room sollte in der Lage sein, diese Datenklasse ordnungsgemäß zu behandeln, da nur ein Konstruktor alle Felder empfängt.
Yigit
2
Stellen Sie sicher, dass der Name und der Typ des Konstruktorparameters mit den Erwartungen von Room übereinstimmen. Dies kann auch bei einem Keyword-Konflikt mit Java auftreten. Zum Beispiel ist das Java-Schlüsselwort staticin Kotlin zulässig, aber wenn es kompiliert wird, sieht es so aus, als würden sie es durch einen anderen Namen ersetzen, was dazu führt, dass der Room Annotation-Prozessor nicht in der Lage ist, die Übereinstimmung mit dem Feld herzustellen.
chRyNaN
Können Sie Ihr DAO auch posten?
Vicky
Sie lösen dieses
Problem

Antworten:

42

Hatte vorher ein ähnliches Problem.

Zuerst habe ich apply plugin: 'kotlin-kapt'gradle aktualisiert / hinzugefügt .

Als nächstes habe ich es anstelle von annotationProcessorGradle verwendet:

kapt "android.arch.persistence.room:compiler:1.0.0-alpha4"

Als letztes musste eine unveränderliche Datenklasse erstellt werden:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    val id : Int,
    val title: String,
    val overview: String,
    val poster_path: String,
    val backdrop_path: String,
    val release_date: String,
    val vote_average: Double,
    val isFavorite: Int
)

AKTUALISIEREN:

Diese Lösung funktioniert, wenn Sie Klassen für das Modell und Klassen für die Datenbank im selben Android-Modul haben. Wenn Sie Modellklassen im Android Library-Modul und den Rest des Codes in Ihrem Hauptmodul haben, erkennt Room diese NICHT.

Tomek Polański
quelle
19
Das Hinzufügen apply plugin: 'kotlin-kapt'zur Moduldatei hat build.gradledas Problem für mich gelöst, danke!
Louis CAD
19
Funktioniert nicht mit Androidx und verwendet 'Plugin anwenden:' kotlin-kapt '
ArdenDev
[Kotlin] Ich hatte dieses Problem bei der Auswahlabfrage, weil ich vergessen habe, den Rückgabetyp in DAO
Sachin
37

In Ihrem Fall ist dies kein Problem, aber bei anderen kann dieser Fehler auftreten, wenn Sie @Ignore-Parameter in Ihrem primären Konstruktor haben, dh Room erwartet Folgendes:

  • parameterloser Konstruktor oder
  • Konstruktor mit allen Feldern, die nicht mit @Ignore markiert sind

zum Beispiel:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String,
    @Ignore var overview: String) 

wird nicht funktionieren. Dieser Wille:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String) 
Daneejela
quelle
2
Dies war mein Fall, aber es macht keinen Sinn, weil das offizielle Beispiel für @Ignore es auf die gleiche Weise verwendet: developer.android.com/training/data-storage/room/defining-data
Aspiring Dev
@AspiringDev Ich stimme zu, klingt eher nach einem Raumfehler als nach absichtlichem Design.
Daneejela
3
Die einzige Möglichkeit ist also, keine @ Ignor-Felder zu verwenden.
FutureShocked
3
@daneejela Sie können auch @IgnoreFelder in Ihrem primären Konstruktor haben. Sie benötigen lediglich einen Konstruktor ohne das Feld, das Room nutzen kann. Siehe meine Antwort für Details.
FutureShocked
1
@Ignorein einem einzelnen Konstruktor ist mit Standardwert und @JvmOverloadsAnmerkung
zulässig
22

Sie müssen einen sekundären Konstruktor wie folgt angeben:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String,
    var overview: String,
    var poster_path: String,
    var backdrop_path: String,
    var release_date: String,
    var vote_average: Double,
    var isFavorite: Int
) {
    constructor() : this(0, "", "", "", "", "", 0.0, 0)
}    
evanchooly
quelle
14

Was hat bei mir funktioniert:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int? = 0,
    var title: String? = "",
    var overview: String? = "",
    var poster_path: String? = "",
    var backdrop_path: String? = "",
    var release_date: String? = "",
    var vote_average: Double? = 0.0,
    var isFavorite: Int? = 0
)
Stevenwood
quelle
10

Für mich war alles, was ich tun musste, der Datenklasse einen Konstruktor hinzuzufügen, an den leere Parameter wie folgt gesendet wurden:

    @Entity(tableName = "posts")
data class JobPost(
    @Ignore
    @SerializedName("companyLogo")
    var companyLogo: String,
    @Ignore
    @SerializedName("companyName")
    var companyName: String,
    @Ignore
    @SerializedName("isAggregated")
    var isAggregated: String,
    @PrimaryKey(autoGenerate = false)
    @SerializedName("jobID")
    var jobID: String,
    @Ignore
    @SerializedName("jobTitle")
    var jobTitle: String,
    @Ignore
    @SerializedName("postedOn")
    var postedOn: String,
    @Ignore
    @SerializedName("region")
    var region: String
) {
    constructor() : this("","","","","","","")
}
Ahmed Awad
quelle
Danke, dies sollte die akzeptierte Antwort sein. @Leonardo Deleon Manchmal tritt das Problem auf, weil wir den Eigenschaften keinen Standardwert zugewiesen haben. e.g: var postedOn: String = "" // this should fix the error as well
Mochadwi
Beantworten Sie nur die für mich funktionierenden @Ignore-Parameter.
error1337
10

Um die Antworten von @evanchooly und @daneejela zu erweitern, benötigen Sie einen sekundären Konstruktor, um @IgnoreParameter in Ihrem primären Konstruktor verwenden zu können. Dies ist so, dass Room immer noch einen Konstruktor hat, den er zum Instanziieren Ihres Objekts verwenden kann. Wenn wir in Ihrem Beispiel eines der Felder ignorieren:

@Entity(tableName = "movies")
data class MovieKt(
        @PrimaryKey
        var id : Int,
        var title: String,
        var overview: String,
        var poster_path: String,
        var backdrop_path: String,
        @Ignore var release_date: String,
        @Ignore var vote_average: Double,
        @Ignore var isFavorite: Int
) {
    constructor(id: Int, title: String, overview: String, poster_path: String, backdrop_path: String) {
        this(id, title, overview, poster_path, backdrop_path, "", 0.0, 0)
    }
}
FutureShocked
quelle
1
Sollte Ihre Syntax nicht seinconstructor(params) : this(params from primary constructor) { }
Sudhir Khanger
10

Ich hatte das gleiche Problem. Sie können die @ Ignore-Felder in den Klassenkörper verschieben. Zum Beispiel :

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String
){
    //here
    @Ignore var overview: String
 }
Thilaw Fabrice
quelle
7

Kotlin erlaubt einen langen Parameternamen, dies funktioniert jedoch nicht, wenn der Raum Java-Code generiert.

Erik B.
quelle
1
Das war mein Problem. Das Ändern meines Längengrads var von 'long' in 'lng' hat den Fehler behoben.
Tom
Die Antwort von API wurde lange für Längengrad verwendet, und es dauerte Stunden, um dies zu lösen.
Thracian
4

Ich denke, dass eine gute Option zur Lösung ist:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int = 0,
    var title: String = "",
    var overview: String = "",
    var poster_path: String = "",
    var backdrop_path: String = "",
    var release_date: String = "",
    var vote_average: Double = 0.0,
    var isFavorite: Int = 0
)
tito
quelle
4

Ich hatte auch dieses Problem, aber ich erkannte, dass das Problem darin bestand, dass ich die Annotation @Embedded zu einer Eigenschaft hinzufügte, die bereits einen Typkonverter hatte. Daher sollte jeder, der das gleiche Problem hat, die Eigenschaftsdeklarationen für Ihre Modellklasse sorgfältig prüfen und sicherstellen, dass das @ Eingebettete Anmerkungen befinden sich nicht in einer Eigenschaft, der ein Typkonverter zugeordnet ist.

Caleb Grimah
quelle
2

Ich hatte dieses Problem mit einer Entität (alle Felder wurden ordnungsgemäß initialisiert, varwie viele der Antworten hier vorschlagen), die eine Liste verwandter, nicht primitiver Elemente wie das OP in dieser SO-Frage enthielt . Zum Beispiel:

@Entity(tableName = "fruits")
data class CachedFruitEntity(
        @PrimaryKey var id: Long = 0L,
        @Embedded(prefix = "buyer_") var buyerEntity: CachedBuyerEntity? = null
        @TypeConverters(VendorsConverter::class)
        var vendorEntities: List<CachedVendorEntity?> = listOf()))

Das heißt, es hat ein eingebettetes Feld, und es dauerte eine Weile, bis mir klar wurde, dass ich stattdessen einen Typkonverter für die Lieferantenentitätsliste benötigte (der Compiler warf nicht das Übliche aus. Error:(58, 31) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.Daher war meine Lösung dieser Antwort sehr ähnlich

Dieser Github-Thread für Google-Architekturkomponenten enthält weitere Informationen zu diesem irreführenden Fehler, ist sich jedoch nicht sicher, ob das Problem bereits behoben wurde.

kip2
quelle
2

Wie in den Room-Dokumenten angegeben, müssen Sie einen leeren öffentlichen Konstruktor erstellen . Wenn Sie andere benutzerdefinierte Konstruktoren deklarieren möchten, müssen Sie gleichzeitig eine @IgnoreAnmerkung hinzufügen .

@Entity
public class CartItem {
    @PrimaryKey
    public int product_id;
    public int qty;

    public CartItem() {
    }

    @Ignore
    public CartItem(int product_id, int count) {
        this.product_id = product_id;
        this.qty = count;
    }
}
Sreekant Shenoy
quelle
2

Heute hatte ich dieses Problem. Ich habe verwendet @Ignore, deshalb habe ich den Fehler bekommen. Um dies zu lösen, habe ich einen sekundären Konstruktor erstellt. Mein Code sieht also ungefähr so ​​aus:

@Entity(tableName = "profile")
data class Profile(
  @field:SerializedName("id") @PrimaryKey @ColumnInfo(name = "id") var id:Long,
  @field:SerializedName("foo") @ColumnInfo(name = "foo") var foo:String?,
  @field:SerializedName("bar") @Ignore var Bar:String?
){
   constructor(id:Long, foo:String) : this(id, foo, null)
}

Das hat bei mir funktioniert.

Qazi Fahim Farhan
quelle
1

https://issuetracker.google.com/issues/62851733

Ich fand, dass dies der Projektionsfehler von @ Relation ist ! kein Kotlin Sprachproblem. basierend auf Google GithubBrowserSample Java ist auch ein Fehler aufgetreten, aber eine andere Fehlermeldung.

Unten ist mein Kotlin-Code:

data class UserWithCommunities(
        @Embedded
        var user: User = User(0, null),

        @Relation(parentColumn = "id",
                entityColumn = "users_id",
                entity = CommunityUsers::class,
                projection = arrayOf("communities_id")) // delete this line.
        var communityIds: List<Int> = emptyList()
)

richtig:

data class UserWithCommunities(
        @Embedded
        var user: User = User(0, null),

        @Relation(parentColumn = "id",
                entityColumn = "users_id",
                entity = CommunityUsers::class)
        var communityList: List<CommunityUsers> = emptyList()
)
Changhao Cui
quelle
1

Gleicher Fehler, viel seltsamere Lösung: Geben Sie den Cursor nicht mit reactivex Maybe<Cursor>auf Ihrem Dao zurück. Flowable, SingleUnd Observablearbeiten entweder nicht.

Beißen Sie einfach in die Kugel und tätigen Sie den reaktiven Anruf außerhalb der Dao-Anfrage. Vor:

@Dao
interface MyDao{
    @Query("SELECT * FROM mydao")
    fun getCursorAll(): Flowable<Cursor>
}

Nach:

@Dao
interface MyDao{
    @Query("SELECT * FROM mydao")
    fun getCursorAll(): Cursor
}

Meta:

Android Studio 3.2
Build #AI-181.5540.7.32.5014246, built on September 17, 2018
JRE: 1.8.0_152-release-1136-b06 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
macOS 10.12.6
Blaze Gawlik
quelle
1

Fügen Sie einfach die folgende Anmerkung zu jedem Konstruktor hinzu, der die Fehler verursacht, und fügen Sie einen neuen leeren Konstruktor hinzu.

@Ignorieren

Harbdollar
quelle
1

Verwenden Sie nicht die Datenklasse, sondern die normale Klasse. Diese Methode wird das Problem lösen

Mustafa
quelle
1

Mit 2.1.0-alpha6 stellte sich heraus, dass es sich in Dao um einen ungültigen Rückgabetyp handelt. Das erwartete Korrigieren des Rückgabetyps wurde behoben.

Vairavan
quelle
1

Für mich habe ich 'lat' & 'long' als Variablennamen in der Datenklasse (Entity) für Kotlin verwendet, sodass es in Breiten- und Längengrad umbenannt wurde.

Funktioniert nicht:

@Entity(tableName = "table_User")
data class User(@PrimaryKey var userId : Int, @ColumnInfo(name = "first_name") 
var firstName: String
            , @ColumnInfo(name = "last_name") var lastName: String
            , @ColumnInfo(name = "password") var password: String
            , @ColumnInfo(name = "dob") var dob: Long
            , @ColumnInfo(name = "address") var address: String
            , @ColumnInfo(name = "lat") var latitude: Double
            , @ColumnInfo(name = "long") var longitude: Double) {

}

Arbeiten:

@Entity(tableName = "table_User")
data class User(@PrimaryKey var userId : Int, @ColumnInfo(name = "first_name") 
var firstName: String
            , @ColumnInfo(name = "last_name") var lastName: String
            , @ColumnInfo(name = "password") var password: String
            , @ColumnInfo(name = "dob") var dob: Long
            , @ColumnInfo(name = "address") var address: String
            , @ColumnInfo(name = "latitude") var latitude: Double
            , @ColumnInfo(name = "longitude") var longitude: Double) {

}
Muhammad Maqsood
quelle
Dies ist auch bei mir der Fall, danke für die Antwort 👍
Muazzam A.
1

Das Kotlin-Plugin erkennt keine AnnotationProcessor-Abhängigkeiten. Verwenden Sie also die neueste Version des Kotlin-Annotation-Prozessors. Fügen Sie diese Zeile oben in die build.gradle Datei auf Modulebene ein

apply plugin: 'kotlin-kapt'

mögen

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'  // add this line

android {
    compileSdkVersion 28
    defaultConfig {
      ........
    }
}

Vergessen Sie nicht, die compileSdkVersion entsprechend zu ändern.

Ekeuwei
quelle
0

Wie in der Raumdatenbank angegebenEntity :

Jede Entität muss entweder einen Konstruktor ohne Argumente oder einen Konstruktor haben, dessen Parameter mit Feldern übereinstimmen (basierend auf Typ und Name).

Wenn Sie also einen leeren Konstruktor hinzufügen und Ihren parametrisierten Konstruktor mit Anmerkungen versehen, @Ignorewird Ihr Problem gelöst. Ein Beispiel:

public class POJO {

    long id;

    String firstName;

    @Ignore
    String lastName;

    public POJO() {
    }

    @Ignore
    public POJO(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    // getters and setters
    // ...

}
Rajarshi
quelle
0

In meinem Fall habe ich in einer der Dao-Abfragen keinen Tipp zurückgegeben. Ich hoffe, es hilft anderen. Danke

Schwarzer Falke
quelle
-2

Für eine Variation der FutureShocked-Antwort, die autoGenerate implementiert:

@Entity(tableName = "movies")
data class MovieKt(
        var title: String,
        var overview: String,
        var poster_path: String,
        var backdrop_path: String,
        @Ignore var release_date: String,
        @Ignore var vote_average: Double,
        @Ignore var isFavorite: Int
) {
@PrimaryKey(autoGenerate = true) var id : Int = 0

    constructor(title: String, overview: String, poster_path: String, backdrop_path: String) {
        this(id, title, overview, poster_path, backdrop_path, "", 0.0, 0)
    }
}
Samuel
quelle