Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Room: related entities - usable public constructor

To get a OneToMany relation with Room I create a POJO with @Embedded object and @Relation variable.

data class SubjectView(
    @Embedded
    var subject: Subject,

    @Relation(parentColumn = "idWeb", entityColumn = "subject_id", entity = Topic::class)
    var topics: List<Topic>?
)

But while compiling I have this error

 error: 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)
[...]
Tried the following constructors but they failed to match:
SubjectView(biz.eventually.atpl.data.db.Subject,java.util.List<biz.eventually.atpl.data.db.Topic>) : [subject : subject, topics : null]

Well, that constructor [subject : subject, topics : null] looks like the good one ???

However, if I change my class with no-arg constructor and an all params constructor, it does work.

class SubjectView() {
    @Embedded
    var subject: Subject = Subject(-1, -1, "")

    @Relation(parentColumn = "idWeb", entityColumn = "subject_id", entity = Topic::class)
    var topics: List<Topic>? = null

    constructor(subject: Subject, topics: List<Topic>?) : this() {
        this.subject = subject
        this.topics = topics
    }
}

I would like to know why the first (quicker) version does not compile, as it is not as the documentation shows.

Default args for all variables (as I could have seen on other post) in a constructor (data) class seems not to be mandatory though?

Thanks

like image 218
Tweety B Avatar asked Oct 26 '17 13:10

Tweety B


1 Answers

There are several topics how data class generate the constructors.

Since you have a nullable Object inside your constructor, it will generate all possible constructors. That means it generates

constructor(var subject: Subject)
constructor(var subject: Subject, var topics: List<Topic>) 

There are two ways to solve that. The first one is to predefine all values like and create another ignored constructor with the desired constructor.

data class SubjectView(
    @Embedded
    var subject: Subject,

    @Relation(parentColumn = "idWeb", entityColumn = "subject_id", entity = Topic::class)
    var topics: List<Topic> = ArrayList()
) {
 @Ignore constructor(var subject: Subject) : this(subject, ArrayList())
}

Another way is creating a half-filled data class like

data class SubjectView(@Embedded var subject: Subject) {
    @Relation var topics: List<Topic> = ArrayList()
}

Take care that the first solution is the proper solution and you need to set @Ignore to any other constructor.

like image 70
Emanuel S Avatar answered Oct 20 '22 00:10

Emanuel S