Reputation: 2554
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
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