web-dev-qa-db-ja.com

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

これはコンパイル時に2回現れますが、どのクラスから来たのかはわかりませんが、(データベースからクラスを削除することで)これがファイルの1つであることがわかりました。主キーがIntではなく文字列(これを使用する2つのクラスの1つ)に関係していると仮定していますが、ドキュメントには問題の内容が示されておらず、実際にはドキュメントに示されていますその文字列は有効な主キーです。

@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-デフォルトのコンストラクターの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.
12
WoogieNoogie

この問題はデバッグが非常に難しく、再現がより困難でしたが、問題が見つかりました。私は@Embeddedオブジェクトを使用していましたが、入っていた結果は実際にはそのオブジェクトのListでした。これは、自動埋め込みタスクに問題を引き起こしていました。そのために作成できる完璧なコンバーターはありませんでした。

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

@Ignoreで注釈を付ける必要がありましたが、代わりに、このリストの結果を独自のテーブルに保存します。現在は新しいテーブルrange_choicesです。

3
WoogieNoogie

あなたの場合の問題は、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)
}

この場合、「内部」で生成されるコンストラクタは2つだけです。 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 Generation をご覧ください。

問題なく動作するクラスをテストした後、別の投稿で、apply plugin: 'kotlin-kapt'あなたのGradleで。

Dateクラスに有効な型コンバーターがあることを再確認してください。 その問題 ずっと前に書いた。

上記のものを再コーディングした後、そのようなUserPermissionsクラスを追加することで問題なく動作しました。

data class UserPermissions(var permissionid: String) 

編集:UserPermissionクラスを使用した後、すべてがうまく機能しました。適切なインポート(sql.Dateの代わりにutil.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"

問題 ずっと前に書いた

16
Emanuel S

主キーは、以下を使用して Annotation Use-site Targets を使用してください。

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

そして

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

ヌル値を許可する値の使用を避け、すべてが何らかのデフォルト値を持つようにしてください。これがこの問題を解決する最も簡単な方法です。

本当に使用したい場合は、それらすべてを含むコンストラクタを作成できます。

0
gyurix