Ошибка базы данных комнаты с классом данных Kotlin

Я переезжаю в комнату, и я столкнулся с проблемой блокировки. Я прошел и исправил все проверки времени компиляции из библиотеки Room, но теперь я вижу следующую ошибку:

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

Это появляется дважды во время компиляции без каких-либо доказательств того, из какого класса это происходит, но я смог выяснить (путем удаления классов из базы данных), что это был один из файлов. Я предполагаю, что это связано с тем, что основной ключ является строкой вместо Int (это один из двух классов, который использует это), но ничто в документации не указывает на то, что проблема будет, и на самом деле документация показывает что строки действительны Первичные ключи.

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

Я пробовал несколько вещей, чтобы попытаться обойти это.

  • Удалите атрибут данных этого класса, чтобы сделать его нормальным POKO
  • Удалите переменные из конструктора по умолчанию и поместите их в класс
  • Удалите Игнорировать из пустого конструктора (обратите внимание, что это вызывает другую проблему, Room cannot pick a constructor since multiple constructors are suitable – аннотация по игнорированию конструктора по умолчанию оборачивается вокруг этого.) Это та часть, которая больше всего меня озадачивает – удаление это говорит о том, что «несколько конструкторов действительны», и в нем говорится, что «никакие конструкторы не действуют».

Обновлено: добавление нескольких дополнительных фрагментов кода из моего проекта.

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' 

Класс базы данных

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

Преобразователи

 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(",") ?: "" } } 

Другой класс данных

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

Класс 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. 

Проблема в вашем случае заключается в том, что если у вас есть значения NULL, Kotlin будет генерировать несколько конструкторов для каждого возможного конструктора.

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

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

Пример:

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

В этом случае только два конструктора будут генерироваться «под капотом». Если у вас есть значения с нулевым значением, у вас будут все доступные конструкторы.

Пример:

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

генерирует

 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 

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

После тестирования вашего класса, который работает безупречно, я нашел в другом посте, что вы должны проверить, используете ли вы apply plugin: 'kotlin-kapt' в вашей Gradle.

Дважды проверьте, что у вас есть действующие преобразователи типов для вашего класса Date. Я написал этот вопрос дольше.

После перекодировки ваших вещей выше он отлично справился, добавив класс UserPermissions:

 data class UserPermissions(var permissionid: String) 

Изменить: после использования вашего класса UserPermission все работало нормально. Пожалуйста, позаботьтесь, если вы используете правильный импорт (util.Date вместо sql.Date, например).

Еще одна проблема заключается в том, что вы используете старую очень багги-библиотеку комнаты.

Текущая версия (при написании этого)

 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" 

Я написал вопрос давно

Старайтесь избегать использования значений с нулевым значением и сделать все свое значение по умолчанию. Это самый простой способ решить эту проблему.

Если вы действительно хотите их использовать, вы можете создать конструктор, содержащий все из них.

Ваши первичные ключи должны быть как указано ниже, используя целевые задания использования аннотации

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

а также

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

Вопрос был чрезвычайно сложным для отладки и более сложного воспроизведения, но я нашел проблему. Я использовал объект @Embedded , но результат, который шел, был фактически List этого объекта. Это создавало проблемы с автоматической задачей Embed, и для нее не было совершенного Конвертера.

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

Я должен был аннотировать это с помощью @Ignore и вместо этого я @Ignore результаты этого списка в своей таблице, а теперь новую таблицу range_choices .