web-dev-qa-db-fra.com

Erreur de la base de données de la pièce avec la classe de données Kotlin

J'ai commencé à utiliser Room et j'ai rencontré un problème de blocage. J'ai parcouru et corrigé tous les contrôles de compilation de la bibliothèque Room, mais je rencontre maintenant l'erreur suivante:

Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type).

Cela apparaît deux fois au moment de la compilation, sans aucune indication de la classe dont elle provient, mais j'ai pu comprendre (en supprimant des classes de la base de données) qu'il s'agissait de l'un des fichiers. Je suppose que cela a quelque chose à voir avec la clé primaire étant une chaîne au lieu d'un int (c'est l'une des deux classes qui l'utilise), mais rien dans la documentation n'indique quel serait le problème, et en fait la documentation montre que les chaînes sont des clés primaires valides.

@Entity(tableName = "inspections")
data class Inspection(
@SerializedName("id")
var id: Int = 0,

...
// Rest of code left off for brevity, found to not be related to the issue.

J'ai essayé quelques trucs pour essayer de contourner ça.

  • Supprimez l'attribut data de cette classe pour en faire un POKO normal
  • Supprimez les variables du constructeur par défaut et placez-les dans la classe
  • Supprimez Ignore du constructeur vide (remarque, ceci pose un problème différent, Room cannot pick a constructor since multiple constructors are suitable - l'annotation Ignore sur un constructeur par défaut contourne cela.) C'est la partie qui me laisse le plus perplexe. le garder dit "aucun constructeur n'est valide".

Mise à jour: Ajout de quelques extraits de code plus pertinents de mon projet.

build.gradle

apply plugin: 'com.Android.application'
apply plugin: 'kotlin-Android'
apply plugin: 'kotlin-Android-extensions'
apply plugin: 'kotlin-kapt'
.....
implementation 'Android.Arch.persistence.room:runtime:1.0.0-alpha9-1'
implementation 'Android.Arch.persistence.room:rxjava2:1.0.0-alpha9-1'
kapt 'Android.Arch.persistence.room:compiler:1.0.0-alpha9-1'

Classe de base de données

@Database(entities =
    arrayOf(Account::class, Category::class,
            Inspection::class, InspectionForm::class,
            InspectionFormItem::class, InspectionFormsStructure::class,
            InspectionItemPhoto::class,
            InspectionItem::class, LineItem::class,
            LocalPhoto::class, Rating::class,
            Structure::class, SupervisoryZone::class,
            Upload::class, User::class),
    version = 16)
@TypeConverters(Converters::class)
abstract class OrangeDatabase : RoomDatabase() {
    abstract fun inspectionDao(): InspectionDao

    abstract fun localDao(): LocalDao

    abstract fun ratingsDao(): RatingsDao

    abstract fun structureZoneDao(): StructureZoneDao

    abstract fun userAccountDao(): UserAccountDao
}

Convertisseurs

class Converters {
@TypeConverter
fun fromTimestamp(value: Long?): Date? {
    return if (value == null) Date() else Date(value)
}

@TypeConverter
fun dateToTimestamp(date: Date?): Long? {
    return date?.time ?: 0
}

@TypeConverter
fun fromStringToArray(value: String?): Array<String>? {
    return value?.split(",")?.toTypedArray() ?: arrayOf()
}

@TypeConverter
fun stringToStringArray(strings: Array<String>?): String? {
    return strings?.joinToString(",") ?: ""
}
}

Une autre classe de données

@Entity(tableName = "users")
data class User(
@PrimaryKey
@SerializedName("id")
var id: Int = 0,

...
// Rest of code left off for brevity, found to not be related to the issue.

Classe UserPermissions:

data class UserPermissions(
@SerializedName("id")
var pid: Int = 0,

...
// Rest of code left off for brevity, found to not be related to the issue.
9
WoogieNoogie

Le problème était extrêmement difficile à résoudre et à reproduire, mais j’ai trouvé le problème. J'utilisais un objet @Embedded, mais le résultat qui était entré était en réalité une List de cet objet. Cela posait des problèmes pour la tâche automatique d'intégration et il n'y avait pas de convertisseur parfait pouvant être écrit pour cela.

@SerializedName("range_choices")
@Embedded
var rangeChoices: List<RangeChoice>? = null,

J'ai dû annoter cela avec @Ignore et à la place, je vais enregistrer les résultats de cette liste dans sa propre table, maintenant la nouvelle table range_choices.

2
WoogieNoogie

Le problème dans votre cas est que, si vous avez des valeurs nullables, Kotlin générera plusieurs constructeurs pour chaque constructeur possible.

Cela signifie que vous devez définir un constructeur par défaut et le renseigner avec les valeurs par défaut. 

Si vous voulez en avoir un autre qui devrait être ignoré, vous devez vous assurer d'utiliser le constructeur parent avec tous ces paramètres.

Exemple:

@Entity(tableName = "inspections")
data class Inspection(
@SerializedName("id")
var id: Int = 0,

@PrimaryKey
@SerializedName("guid")
var guid: String = "",

@SerializedName("score")
var score: Double = 0.0,

@SerializedName("notification_sent_at")
var notificationSentAt: Date = Date(),

var wasUploaded: Boolean = false)  {

@Ignore
constructor() : this(0, "", 0.0, Date(), false)
}

Dans ce cas, seuls deux constructeurs seront générés "sous le capot". Si vous avez des valeurs nullables, vous aurez tous les constructeurs possibles disponibles.

Exemple:

data class Test(var id: Int = 0, var testString: String? = null, var testBool : Boolean? = null) {
   constructor(0)
} 

génère 

constructor(var id:Int)
constructor() : this(0)
constructor(var id:Int, var testString: String)
constructor(var id:Int, var testBool: Boolean) 
constructor(var id:Int, var testString: String, var testBool : Boolean)
// .. and so on

Puisque vous recherchez une documentation officielle, vous voudrez peut-être regarder Génération de surcharges .

Après avoir testé votre classe, qui fonctionne parfaitement, j’ai trouvé dans un autre message que vous devez vérifier si vous avez utilisé apply plugin: 'kotlin-kapt' dans votre Gradle.

Vérifiez à nouveau que vous avez des convertisseurs de type valides pour votre classe Date. J'ai écrit ce problème il y a plus longtemps.

Après avoir recodé vos fichiers ci-dessus, cela a bien fonctionné en ajoutant une classe UserPermissions comme celle-ci:

data class UserPermissions(var permissionid: String) 

Edit: Après avoir utilisé votre classe UserPermission, tout a bien fonctionné. Faites attention si vous utilisez l'importation appropriée (util.Date au lieu de sql.Date par exemple).

Un autre problème est que vous utilisez une vieille bibliothèque de pièces très boguée. 

La version actuelle (en écrivant ceci) est

implementation "Android.Arch.persistence.room:runtime:1.0.0-beta2"
kapt "Android.Arch.persistence.room:compiler:1.0.0-beta2"
implementation "Android.Arch.persistence.room:rxjava2:1.0.0-beta2"

J'ai écrit un problème il y a longtemps 

13
Emanuel S

Vos clés primaires doivent ressembler à celles données ci-dessous avec Cibles du site d'utilisation d'annotation

@field:PrimaryKey @field:SerializedName("guid") var guid: String = ""

et 

@field:PrimaryKey @field:SerializedName("id") var id: Int = 0
1
Muzammil Husnain

Essayez d'éviter d'utiliser des valeurs nullables et faites en sorte que tout ait une sorte de valeur par défaut. C'est le moyen le plus simple de résoudre ce problème.

Si vous voulez vraiment les utiliser, vous pouvez créer un constructeur les contenant tous.

0
gyurix