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

Я перехожу к использованию Room, и у меня возникла проблема с блокировкой. Я выполнил и исправил все проверки времени компиляции из библиотеки 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.
  • Удалите переменные из конструктора по умолчанию и поместите их в класс
  • Удалите Ignore из пустого конструктора (обратите внимание, это вызывает другую проблему, Room cannot pick a constructor since multiple constructors are suitable - аннотация Ignore в конструкторе по умолчанию обходит это.) Это часть, которая меня больше всего смущает - удаление этого говорит, что "несколько конструкторов действительны", в нем говорится, что "конструкторы не действительны".

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

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.

person WoogieNoogie    schedule 16.10.2017    source источник


Ответы (4)


Проблема в вашем случае заключается в том, что если у вас есть значения, допускающие значение 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)
}

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

Пример:

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

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

После тестирования вашего класса, который работает безупречно, я обнаружил в другом сообщении, что вам нужно проверить, использовали ли вы 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"

Я давно написал проблему

person Emanuel S    schedule 18.10.2017
comment
Сообщение об ошибке, с которым я сталкиваюсь в библиотеке 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). То, что вы предлагаете, и то, что я обнаружил, заключается в том, что все эти конструкторы существуют, в том числе тот, у которого все параметры соответствуют полям. - person WoogieNoogie; 18.10.2017
comment
Я добавил ваш класс в свой проект, и он работает безупречно. Даже после очистки проекта, аннулирования кеша и т. Д. Не могли бы вы опубликовать свои файлы Gradle - person Emanuel S; 18.10.2017
comment
Я разместил соответствующий фрагмент Gradle, а также несколько других файлов в реализации. - person WoogieNoogie; 19.10.2017
comment
Опубликуйте, пожалуйста, класс UserPermissions. Я полностью перекодировал ваш материал выше, и он отлично компилируется, добавив класс UserPermissions, который содержит только идентификатор разрешения в качестве параметра. - person Emanuel S; 19.10.2017
comment
В сообщение добавлен полный класс UserPermissions. Очень странно, что вы можете использовать все без проблем. - person WoogieNoogie; 20.10.2017
comment
Обновил мой ответ - person Emanuel S; 20.10.2017
comment
Я обновился до последней версии (на данный момент самая новая версия - rc1), и появляется та же проблема. Обновление выявило несколько проблем с двумя моими классами, имеющими переменную PrimaryKey, допускающую значение NULL, но после ее исправления одно и то же сообщение об ошибке появляется два раза без какого-либо контекста. - person WoogieNoogie; 21.10.2017
comment
После перехода на rc1 вам необходимо очистить свой проект, аннулировать кеш и перезапустить - person Emanuel S; 21.10.2017
comment
Сделали это несколько раз. По-прежнему получаю ту же глупую ошибку. - person WoogieNoogie; 21.10.2017
comment
Спасибо за вашу помощь, я наконец смог сузить круг вопросов. Оставил ответ на ответ, но наградил вас наградой за отличную помощь в устранении неполадок. Еще раз спасибо! - person WoogieNoogie; 21.10.2017
comment
Все еще не уверен, почему эти ошибки начали исчезать, когда я удалял ДРУГИЕ классы, которые на самом деле не были причиной. Это то, что изначально заставило меня поверить, что проблема была в классе, вставленном в исходный вопрос. - person WoogieNoogie; 21.10.2017
comment
Спасибо, и спасибо, что разместили ответ. Что касается сложности отладки, я оставил проблему несколько месяцев назад (сразу после выпуска) в aac github ;-) ive потратил два дня на поиск этой проблемы давным-давно - person Emanuel S; 21.10.2017
comment
Вы уверены, что если у вас есть значения, допускающие значение NULL, Kotlin сгенерирует несколько конструкторов для каждого возможного конструктора? В документации говорится, что они созданы для параметров со значениями по умолчанию, независимо от их допустимости NULL, и создается не более одного (пустого) конструктора без @JvmOverloads. - person gmk57; 25.05.2020

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

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

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

person WoogieNoogie    schedule 21.10.2017
comment
Это работает .. +1. Фактически для тех, кто не хочет использовать игнорирование, вы можете просто указать свой преобразователь типов, но не включать @Embedded для списка объектов. - person Rat-a-tat-a-tat Ratatouille; 28.09.2018

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

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

а также

@field:PrimaryKey @field:SerializedName("id") var id: Int = 0
person Muzammil Husnain    schedule 19.10.2017
comment
Вы уверены, что понимаете использование аннотаций на основе котлина? ;-) - person Emanuel S; 19.10.2017
comment
@EmanuelS Будет хорошо с вашей стороны, если вы укажете точную проблему при использовании аннотаций на основе котлина. Я также приложил официальный документ. - person Muzammil Husnain; 20.10.2017

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

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

person gyurix    schedule 18.10.2017