nuoritoveri
nuoritoveri

Reputation: 2554

Model class used as a field type in itself causes error in Ebean

I'm using Play Framework 2.4. I want to model a set of classes with this inheritance chain:

Research <- Publication <- Article

The problem is, I would like the Publication class to refer to the other objects of this class, like this:

@MappedSuperclass
public abstract class Research extends Model {
    @Id
    public Long id;
}

@Entity
public class Publication extends Model {
    @ManyToOne
    public Publication translationOf;
}

This works when I don't inherit from Publication. When I add inheriting from Article:

@MappedSuperclass
public abstract class Publication extends Model {
    @ManyToOne
    public Publication translationOf;
}

@Entity
public class Article extends Publication { }

I get:

java.lang.RuntimeException: Error with association
to [class models.research.Publication]
from [models.research.publication.Article.translationOf]. 
Is class models.research.Publication registered?

I thought that maybe configuring the InheritanceType explicity will help, but adding @Inheritance tag causes NullPointerException without any other informative nested exceptions in the stacktrace. This happens for example in this case:

@MappedSuperclass
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype", discriminatorType = DiscriminatorType.STRING)
public abstract class Research extends Model {
    @Id
    public Long id;
    public String dtype;
}

@Entity
@DiscriminatorValue("P")
public class Publication extends Model {
    @ManyToOne
    public Publication translationOf;
}

Upvotes: 1

Views: 370

Answers (1)

Koen De Groote
Koen De Groote

Reputation: 111

In your first example, Publication is an @Entity. After that it's suddenly a @Mappedsuperclass

I don't understand what you want here. Do you want one publication to be linked to other publications? Because that's a ManyToMany relationship.

And for ManyToMany relationships, you need to specify the "mappedBy" argument.

Same for articles and publications. One Article could appear in many Publications and many publications could have the same article.

Unless it has to be specifically different for your setup?

EDIT: Played around with it a bit, this setup works:

@MappedSuperclass
public abstract class Research extends Model {

    @Id
    public Long id;
}


@Entity
public class Publication extends Research {

    @ManyToMany(cascade = CascadeType.ALL, mappedBy = "myReferences")
    // What other publications refer to this one?
    public List<Publication> referencedBy;

    @ManyToMany(cascade = CascadeType.ALL)
    @JoinTable(
            name = "CROSS_REFERENCE",
            joinColumns = {
                    @JoinColumn(name = "MY_ID")
                    },
            inverseJoinColumns = {
                    @JoinColumn(name = "REFERENCER_ID")
            })
    // What publications am I referring to?
    public List<Publication> myReferences;

    // The list of articles in this publication.
    @ManyToMany(cascade = CascadeType.ALL)
    public List<Article> articles;
}


@Entity
public class Article extends Research {

    // The publications this article appears in.
    @ManyToMany(cascade = CascadeType.ALL, mappedBy = "articles")
    public List<Publication> publications;
}

ManyToMany relations always need have an "owner".

In the publication-to-publication case, it is the myReferences field. This is why the "referencedBy" field has the "mappedBy" argument in the @ManyToMany annotation.

A publication can't know ahead of time what future publications will reference them and past publications won't change to reference this new one.

So you can only ever say of a new publication which old ones it is referencing.

And which articles it contains.

You can add in both directions, but it is generally a best practice to use 1 direction and stick to it.

Hope it helps.

Upvotes: 2

Related Questions