Is there multilevel structure in hibernate - java

How to design following structure of beans if I have to Question which has sub Questions and all questions and subquestions has respective answer. Structure is like
Structure
How I can design this structure in hibernate for achieving functionality in spring boot.

If we take into consideration that these are 3 different tables, what I would think would be an entity of Question
#Entity
#Table("question")
public class Question
then an entity of SubQuestion
#Entity
#Table("sub_question")
public class SubQuestion
with ManyToOne assosiation
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="QUESTION_ID")
private Question question;
and finally a generic class GenericAnswer
#Entity
#Table(name = "answer")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "question", discriminatorType = DiscriminatorType.STRING)
public class GenericAnswer {
which will be extended by 2 classes, QuestionAnswer and SubQuestionAnswer
These 2 classes have a discriminator column to distinguish the table they refer to (question or sub_question)
#DiscriminatorValue("question")
#Entity
public class QuestionAnswer extends GenericAnswer {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="QUESTION_ID")
private Question question;
and
#DiscriminatorValue("sub_question")
#Entity
public class SubQuestionAnswer extends GenericAnswer {
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="QUESTION_ID")
private SubQuestion subQuestion;
Hope this helps you.

Related

About inheritance mapping and best practices in Java

I'm learning about the ways of mapping inheritance from database to java with JPA/Hibernate. I've found several examples of how to do it, but not how to apply it.
Now, I'm trying to apply this knowledge on a small project, but I run into a problem where I can't do it the way I thought it would be ideal.
About the code below, the problem is: I have an "Expense" class that records a new expense (credit card debt, etc.), this debt has a creditor, which can be a person (PF) or institution (PJ). A expense has only one creditor, but I'm forced to model with one of each subclass.
#Data
#Entity
#Table(name = "expense")
public class Expense {
// CODE
#ManyToOne
#JoinColumn(name = "creditorPF")
private CreditorPF creditorPF;
#ManyToOne
#JoinColumn(name = "creditorPJ")
private CreditorPJ creditorPJ;
}
#Data
#Entity
#Table(name = "creditor")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Creditor {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "idCreditor")
protected Long id;
#NonNull
protected String description;
}
#Getter
#Setter
#Entity
#Table(name = "creditor_pf")
#PrimaryKeyJoinColumn(name = "idCreditor")
public class CreditorPF extends Creditor {
private String cpf;
#Builder
public CreditorPF() {
super("");
}
#Builder
public CreditorPF(String cpf, String nome) {
super(nome);
this.cpf = cpf;
}
}
#Getter
#Setter
#Entity
#Table(name = "creditor_pj")
#PrimaryKeyJoinColumn(name = "idCreditor")
public class CreditorPJ extends Creditor {
private String cnpj;
#Builder
public CreditorPJ(String cnpj, String nome) {
super(nome);
this.cnpj = cnpj;
}
#Builder
public CreditorPJ() {
super("");
}
}
This works fine, but I don't think it's a good design, because the design is allowing one more creditor per subclass, even if I add validations to prevent it, the design would be semantically incorrect.
Is there a way I can get a design like this code below, but that I can get the subclass information when I retrieve the object through hibernate?
#Data
#Entity
#Table(name = "expense")
public class Expense {
// CODE
#ManyToOne
#JoinColumn(name = "creditor")
private Creditor creditor;
}
In case of getting the Credit type from THROUGH the Expense Object ,there's no way besides using instanceof or getClass() as #Chris said ,btw it's preferable to use composition over inheritence,since it doesn't introduce this problem and preserves database consistency since you can"t be FORCED to have nullable fields, and in your case you can implement it using a class Creditor containing an enum which holds the creditor type since it's know to you ,hope this helps !

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

JPA Entity inheritance with two DiscriminatorColumn

I need your help.
I have the following table of values that I want with JPA map.
I have considered the following class structure.
The classes "NotificationCustomShippingPlan" and "PreviewCustomShippingPlan" get everyone a DiscriminatorValue for DiscriminatorColumn "Type".
But the classes "ActivResultCustomShippingPlan" and "ActivResultCustomShippingPlan" should get other DiscriminatorColumn "SubType".
How can I so what map?
My feeling told me that it is not possible.
EDIT:
#Entity
#Inheritance
#DiscriminatorColumn(name = "TYPE")
#Table(name = "CC_CUSTOM_SHIPPING_PLAN")
public abstract class AbstractCustomShippingPlan {
....
....
}
#Entity
#DiscriminatorValue("NOTIFICATION")
public class NotificationCustomShippingPlan extends AbstractCustomShippingPlan
#Entity
#DiscriminatorValue("PREVIEW")
public class PreviewCustomShippingPlan extends AbstractCustomShippingPlan
#Entity
#DiscriminatorValue("RESULTS")
#DiscriminatorColumn(name = "SUBTYPE")
public abstract class ResultCustomShippingPlan extends AbstractCustomShippingPlan {
#Enumerated(EnumType.STRING)
#Column(name = "CC_CSP_SUBTYPE")
private ServiceType.Subtype subtype;
}
#Entity
#DiscriminatorValue("ACTIVE")
public class ActivResultCustomShippingPlan extends ResultCustomShippingPlan{
.....
}
#Entity
#DiscriminatorValue("REPORTED")
public class ReportedResultCustomShippingPlan extends ResultCustomShippingPlan {
....
}

JPA 2.1 #ForeignKey in inheritance class

I'm migrating to JPA 2.1 and I would like to replace #org.hibernate.annotations.ForeignKey to something in inheritance class.
In fields, ok:
#ManyToOne
#JoinColumn(name = "any_columm_field_id",
foreignKey = #javax.persistence.ForeignKey(name = "any_name_field_fk"))
But in inheritance class, how to do it?
Example code:
Super class
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
#Table(name = "ANY_SUPER_TABLE_NAME")
public abstract class AnySuperClass { }
Specific class
#Entity
#Table(name = "ANY_SPECIFIC_TABLE_NAME")
// TODO Replace to JPA 2.1
// #org.hibernate.annotations.ForeignKey(name = "any_specific_any_super_fk")
public class AnySpecificClass extends AnySuperClass { }
Any help?
Thank you for your time.
According to the doc this should do it:
#Entity
#Table(name = "ANY_SPECIFIC_TABLE_NAME")
#PrimaryKeyJoinColumn(foreignKey = #ForeignKey(name = "any_specific_any_super_fk"))
public class AnySpecificClass extends AnySuperClass { }
It's not easy to find the answer though, with the embedded annotation... it's not obvious where you should be using it.
Not sure this will help you a year later...

javax.persistence annotations and inheritance

I have 4 persistent classes which all have the same fields (exactly) the only 3 difference between them is 1) the class name, 2) the table name and 3) the data. i am aware that this might seem strange to some but trust me there is a good reason which i won't go into here.
now, i'm using hibernate annotations to configure my class which should work like so:
#Entity
#Table(name = "store")
public class Store
{
#Id
#Column(name = "unique_id")
protected String id;
#Column
protected String category;
...
}
.. and this does work, for a single stand-alone class, however there are many fields to map and i'd like to do it all in one hit for all four similar classes, ie:
public class StoreBase
{
#Id
#Column(name = "unique_id")
protected String id;
#Column
protected String category;
...
}
#Entity
#Table(name = "store1")
public class Store1 extends StoreBase
{}
#Entity
#Table(name = "store2")
public class Store2 extends StoreBase
{}
#Entity
#Table(name = "store3")
public class Store3 extends StoreBase
{}
#Entity
#Table(name = "store4")
public class Store4 extends StoreBase
{}
however when attempting this i get the following exception:
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: package.entities.Store1
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:672)
at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:546)
at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:291)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1292)
at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867)
i'm guessing this is because the super class is not being searched for the identifier?
is there a way to utilise inheritance in this context?
thanks, paul.
#MappedSuperclass
public class StoreBase
See docs for more info.
Have a look at #MappedSuperclass.

Categories