房间持久性:错误:实体和Pojos必须具有可用的公共构造函数

时间:2017-06-11 15:38:58

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

我正在将项目转换为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必须具有可用的公共构造函数。您可以拥有一个空构造函数或其参数与字段匹配的构造函数(按名称和类型)。   找不到字段的setter。

我找到的例子离this

不远

如何解决它的想法?

28 个答案:

答案 0 :(得分:40)

之前有过类似的问题。

首先,我已将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将无法识别它们。

答案 1 :(得分:15)

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

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

答案 2 :(得分:8)

对我有用的是什么:

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

答案 3 :(得分:4)

我认为解决问题的一个好方法是:

foreach(NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
    {
       if(ni.NetworkInterfaceType == NetworkInterfaceType.Wireless80211 || ni.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
       {
           Console.WriteLine(ni.Name);
           foreach (UnicastIPAddressInformation ip in ni.GetIPProperties().UnicastAddresses)
           {
               if (ip.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
               {
                   Console.WriteLine(ip.Address.ToString());
               }
           }
       }  
    }

答案 4 :(得分:3)

Kotlin允许使用长名称作为参数名,但是当房间生成Java代码时,这将不起作用。

答案 5 :(得分:2)

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

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

答案 6 :(得分:2)

就像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;
    }
}

答案 7 :(得分:2)

今天我遇到了这个问题。我使用了@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)
}

这对我有用。

答案 8 :(得分:2)

我也遇到了这个问题,但是我意识到问题是我在已经具有类型转换器的属性中添加了@Embedded批注,因此任何有相同问题的人都应仔细检查模型类的属性声明,并进行确保@Embedded注释不在具有与其关联的类型转换器的属性上。

答案 9 :(得分:1)

我遇到了一个实体的问题(所有字段都已正确初始化var,就像这里提出的很多答案一样),其中包含一个相关的非原始项目列表,例如此处的OP { {3}}。例如:

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

也就是说,它有一个嵌入式字段,我花了一段时间才意识到我实际需要的是供应商实体列表的类型转换器(编译器没有抛出通常的{{1}所以我的解决方案与SO question

非常相似

this answer有关于此误导性错误的更多信息,但不确定问题是否已修复。

答案 10 :(得分:1)

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

我发现这是@ Relation的 投影 错误! 不是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()
)

答案 11 :(得分:1)

Kotlin插件不会获取注释处理器的依赖性,因此请使用最新版本的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。

答案 12 :(得分:1)

答案 13 :(得分:0)

就我而言,我有@Ignore 标签和“kotlin-kapt”插件,但在更新到 kotlin1.5.0 版本后,这仍然开始发生。< /p>

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

答案 14 :(得分:0)

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

我的数据库中的 id 类型是 String,我将 dao 从:

try 
        {
            Message message = new MimeMessage(session);
            message.setFrom(new InternetAddress(FromMail));
            message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(ToMail));
            message.setSubject(SubjectMail);
            //message.setText(ContentMail);
            
            MimeBodyPart messageBodyPart = new MimeBodyPart();
            messageBodyPart.setText(ContentMail);
            
            Multipart multipart = new MimeMultipart();
            multipart.addBodyPart(messageBodyPart);
            
            messageBodyPart = new MimeBodyPart();
            
            DataSource source = new FileDataSource(AttachmentPath);
            
            messageBodyPart.setDataHandler(new DataHandler(source));
            messageBodyPart.setFileName(attachment_name.getText());
            
            multipart.addBodyPart(messageBodyPart);
                        
            message.setContent(multipart);
            
            Transport.send(message);
            
            JOptionPane.showMessageDialog(null, "success, message sent!");
        } 
        catch (Exception exp) 
        {
           JOptionPane.showMessageDialog(null, exp);
        }
}

private void attachmentActionPerformed(java.awt.event.ActionEvent evt) {                                           
        // TODO add your handling code here:
        
        JFileChooser chooser = new JFileChooser();
        chooser.setMultiSelectionEnabled(true);
        
        Component frame = null;
        chooser.showOpenDialog(frame);
        
        File file = chooser.getSelectedFile();
        AttachmentPath = file.getAbsolutePath();
        
        //path_attachment.setText(AttachmentPath);
        path_attachment_area.setText(AttachmentPath);
    } 

String AttachmentPath;

致:

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

答案 15 :(得分:0)

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

这导致了 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

答案 16 :(得分:0)

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

答案 17 :(得分:0)

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

答案 18 :(得分:0)

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

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

答案 19 :(得分:0)

要扩展@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)
    }
}

答案 20 :(得分:0)

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

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

例如:

template

不起作用。这将:

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

答案 21 :(得分:0)

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

不起作用:

(Name, Food)

工作:

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

}

答案 22 :(得分:0)

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

答案 23 :(得分:0)

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

答案 24 :(得分:0)

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

}

答案 25 :(得分:0)

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

  

@忽略

答案 26 :(得分:0)

相同的错误,更陌生的解决方案:不要在Dao上使用reactx Maybe<Cursor>返回游标。 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

答案 27 :(得分:-2)

有关实现自动生成的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)
    }
}