【问题标题】:Room Persistence: Error:Entities and Pojos must have a usable public constructor房间持久性:错误:实体和 Pojos 必须有一个可用的公共构造函数
【发布时间】:2017-11-13 02:45:26
【问题描述】:

我正在将一个项目转换为 Kotlin,并且我正在尝试使我的模型(也是我的实体)成为一个数据类 我打算使用 Moshi 转换来自 API 的 JSON 响应

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

由于以下错误,我无法构建应用程序

实体和 Pojos 必须有一个可用的公共构造函数。您可以有一个空的构造函数或参数与字段匹配的构造函数(按名称和类型)。 找不到字段的设置器。

我发现的例子和this不远

关于如何解决的想法?

【问题讨论】:

  • 这是哪个 kotlin 版本?您还可以打印完整的错误消息吗? Room 应该能够正确处理该数据类,因为它只有 1 个接收所有字段的构造函数。
  • 确保构造函数参数的名称和类型与 Room 所期望的一致。这也可能发生在与 Java 的关键字冲突中。例如,Java 关键字 static 在 Kotlin 中是允许的,但是当它被编译下来时,看起来他们用另一个名称替换它,导致 Room 注释处理器无法与该字段匹配。
  • 你也可以发布你的 DAO 吗?
  • 你解决这个问题,添加空白构造函数

标签: android kotlin android-room android-architecture-components


【解决方案1】:

你需要像这样指定一个辅助构造函数:

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

【讨论】:

  • 谢谢!我必须添加constructor() ...@PrimaryKey 并将val 替换为var。代替constructor(),您可以设置默认值,例如var title: String = ""
【解决方案2】:
【解决方案3】:

我认为解决它的一个好选择是:

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

【讨论】:

    【解决方案4】:

    什么对我有用:

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

    【讨论】:

      【解决方案5】:

      之前遇到过类似的问题。

      首先,我已将apply plugin: 'kotlin-kapt' 更新/添加到 gradle。

      接下来,我在 gradle 中使用它而不是 annotationProcessor

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

      最后一件事是创建一个不可变的数据类:

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

      更新:

      当您在同一个 Android 模块中有模型类和数据库类时,此解决方案有效。如果您在 Android 库模块中有模型类,而主模块中有其余代码,Room 将无法识别它们。

      【讨论】:

      • apply plugin: 'kotlin-kapt' 添加到模块的build.gradle 文件为我解决了这个问题,谢谢!
      • 不适用于 androidx 并使用 'apply plugin: 'kotlin-kapt'
      • [Kotlin] 我在选择查询时遇到了这个问题,因为我忘记在 DAO 中添加返回类型
      【解决方案6】:

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

      我发现这是 @Relation 的 projection 错误! 不是 Kotlin 语言问题。 基于 google GithubBrowserSample java 也发生错误,但错误消息不同。

      下面是我的 kotlin 代码:

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

      右:

      data class UserWithCommunities(
              @Embedded
              var user: User = User(0, null),
      
              @Relation(parentColumn = "id",
                      entityColumn = "users_id",
                      entity = CommunityUsers::class)
              var communityList: List<CommunityUsers> = emptyList()
      )
      

      【讨论】:

        【解决方案7】:

        我遇到了一个实体的问题(所有字段都已正确初始化vars,就像这里的许多答案所暗示的那样),其中包括一个相关的非原始项目列表,例如 SO question 中的 OP有。例如:

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

        也就是说,它有一个嵌入式字段,我花了一段时间才意识到我真正需要的是供应商实体列表的类型转换器(编译器没有抛出通常的 Error:(58, 31) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it. 所以我的解决方案与this answer非常相似

        google architecture components github thread 提供有关此误导性错误的更多信息,但不确定该问题是否已得到修复。

        【讨论】:

          【解决方案8】:

          我也遇到过这个问题,但我意识到问题是我将@Embedded 注释添加到了一个已经有类型转换器的属性中,所以任何有同样问题的人都应该仔细检查你的模型类的属性声明并制作确保 @Embedded 注释不在具有与之关联的类型转换器的属性上。

          【讨论】:

            【解决方案9】:

            Kotlin 允许使用 long as 参数名称,但是当 room 生成 java 代码时这将不起作用。

            【讨论】:

            • 这是我的问题。将我的经度变量从“long”更改为“lng”修复了错误。
            • 同样,来自 api 的响应使用 long 作为经度,解决这个问题需要几个小时。
            【解决方案10】:

            对我来说,我所要做的就是向数据类添加一个构造函数,并将空参数发送给它,如下所示:

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

            【讨论】:

            • 谢谢,这应该是公认的答案。 @Leonardo Deleon 有时会出现问题,因为我们没有为属性分配默认值。 e.g: var postedOn: String = "" // this should fix the error as well
            • 只有使用@Ignore 参数对我有用的答案。
            【解决方案11】:

            同样的错误,更奇怪的解决方案:不要在你的 Dao 上使用 reactivex Maybe&lt;Cursor&gt; 返回光标。 FlowableSingleObservable 也不起作用。

            只需硬着头皮在 Dao 请求之外进行响应式调用。 之前:

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

            之后:

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

            元:

            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
            

            【讨论】:

              【解决方案12】:

              只需将以下注释添加到任何导致错误的构造函数并添加一个新的空白构造函数。

              @忽略

              【讨论】:

                【解决方案13】:

                Room Database Entity中所述:

                每个实体必须有一个无参数构造函数或一个构造函数 其参数匹配字段(基于类型和名称)。

                因此,添加一个空的构造函数并使用 @Ignore 注释您的参数化构造函数将解决您的问题。一个例子:

                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
                    // ...
                
                }
                

                【讨论】:

                  【解决方案14】:

                  不要使用数据类,而是使用普通类。这个方法可以解决问题

                  【讨论】:

                    【解决方案15】:

                    在 2.1.0-alpha6 中,它被证明是 Dao 中的无效返回类型。按预期修复返回类型修复它。

                    【讨论】:

                      【解决方案16】:

                      对我来说,我在 kotlin 的 data(Entity) 类中使用 'lat' 和 'long' 作为变量名,所以重命名为纬度和经度就可以了。

                      不工作:

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

                      工作:

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

                      【讨论】:

                      • 我也是这个情况,谢谢解答?
                      【解决方案17】:

                      在您的情况下这不是问题,但对于其他人来说,如果您的主构造函数中有 @Ignore 参数,则可能会发生此错误,即 Room 期望有:

                      • 无参数构造函数或
                      • 所有字段均未标记@Ignore 的构造函数

                      例如:

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

                      不会工作。这将:

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

                      【讨论】:

                      • 这是我的情况,但它没有意义,因为@Ignore 的官方示例使用相同的方式:developer.android.com/training/data-storage/room/defining-data
                      • @AspiringDev 我同意,这听起来更像是一个房间错误,而不是有意的设计。
                      • 所以唯一的选择是不使用@Ignore 字段?
                      • @daneejela 您也可以在主构造函数中拥有 @Ignore 字段,您只需要 some 构造函数而不需要 Room 可以利用的字段。详情见我的回答。
                      • @Ignore 在具有默认值和 @JvmOverloads 注释的单个构造函数 is allowed
                      【解决方案18】:

                      要扩展@evanchooly 和@daneejela 提供的答案,您需要一个辅助构造函数才能在主构造函数中使用@Ignore 参数。这样 Room 仍然有一个构造函数,它可以在实例化对象时使用。根据您的示例,如果我们忽略其中一个字段:

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

                      【讨论】:

                      • 你的语法不应该是constructor(params) : this(params from primary constructor) { }
                      【解决方案19】:

                      我有同样的问题。您可以将@Ignore 字段移动到类主体。例如:

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

                      【讨论】:

                      • 对我来说,我必须为 Ignore 属性分配默认值。
                      【解决方案20】:

                      关于实现 autoGenerate 的 FutureShocked 答案的变体:

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

                      【讨论】:

                        【解决方案21】:

                        就像 Room 文档中所说的那样,您需要创建一个空的公共构造函数。同时,如果要声明其他自定义构造函数,则必须添加@Ignore注解。

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

                        【讨论】:

                          【解决方案22】:

                          Kotlin 插件不获取 annotationProcessor 依赖项,因此请使用最新版本的 Kotlin 注释处理器 - 将此行放在 模块级别的顶部 build.gradle 文件

                          apply plugin: 'kotlin-kapt'

                          喜欢

                          apply plugin: 'kotlin-android'
                          apply plugin: 'kotlin-android-extensions'
                          apply plugin: 'kotlin-kapt'  // add this line
                          
                          android {
                              compileSdkVersion 28
                              defaultConfig {
                                ........
                              }
                          }
                          

                          不要忘记相应地更改 compileSdkVersion。

                          【讨论】:

                            【解决方案23】:

                            今天我遇到了这个问题。我使用了@Ignore,这就是我得到错误的原因。为了解决这个问题,我创建了一个辅助构造函数。所以我的代码看起来像这样:

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

                            这对我有用。

                            【讨论】:

                              【解决方案24】:

                              在我的情况下,我没有在 Dao 查询中返回类型,希望它可以帮助其他人 谢谢

                              【讨论】:

                                【解决方案25】:

                                确保room数据库column名称和constructor中的字段名称相同

                                【讨论】:

                                  【解决方案26】:

                                  我花了一个小时试图解决这个问题,但没有成功。这就是我发现的。我忘了在我的一个查询中添加返回类型

                                  这导致 POJO 错误

                                  @Query("SELECT userNote FROM CardObject WHERE identifier = :identifier")
                                  suspend fun getUserNote(identifier: String)
                                  

                                  没有 POJO 错误

                                  @Query("SELECT userNote FROM CardObject WHERE identifier = :identifier")
                                  suspend fun getUserNote(identifier: String): String
                                  

                                  【讨论】:

                                    【解决方案27】:

                                    我遇到了同样的问题,原因是我在 dao 中通过查询获得的数据类型不等于我返回的数据类型。

                                    我的数据库中的 id 类型是 String,我将 dao 更改为:

                                    @Query("SELECT id FROM content_table")
                                    fun getIds(): Flow<List<Int>>
                                    

                                    收件人:

                                    @Query("SELECT id FROM content_table")
                                    fun getIds(): Flow<List<String>>
                                    

                                    【讨论】:

                                      【解决方案28】:

                                      在我的情况下,我有 @Ignore Tags 和 'kotlin-kapt' 插件,但在更新到 kotlin 到版本 1.5.0 后仍然开始发生这种情况。

                                      我最终将我的房间库从版本 2.2.5 更新到 2.3.0 并且问题得到了解决。

                                      【讨论】:

                                        【解决方案29】:

                                        对于这个问题,我遇到了同样的问题。

                                        Room 依赖项替换为the official docs 中最新的依赖项

                                        【讨论】:

                                        猜你喜欢
                                        • 1970-01-01
                                        • 2019-11-03
                                        • 2017-11-20
                                        • 2019-05-21
                                        • 1970-01-01
                                        • 2019-09-14
                                        • 2018-10-19
                                        • 1970-01-01
                                        • 2018-03-17
                                        相关资源
                                        最近更新 更多