Hibernate+Inheritance
Hibernate+Inheritance
Using the MappedSuperclass strategy, inheritance is only evident in the class, but not
the entity model.
Let's start by creating a Person class which will represent a parent class:
@MappedSuperclass
public class Person {
@Id
private long personId;
private String name;
@Entity
public class MyEmployee extends Person {
private String company;
// constructor, getters, setters
}
In the database, this will correspond to one “MyEmployee” table with three columns
for the declared and inherited fields of the sub-class.
If we're using this strategy, ancestors cannot contain associations with other entities.
2
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
3
2
import javax.persistence.Column;
3 import javax.persistence.DiscriminatorColumn;
import javax.persistence.DiscriminatorType;
4 import javax.persistence.Entity;
import javax.persistence.Id;
5 import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
6
import javax.persistence.Table;
7 @Entity
@Table(name="payment")
8 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "paymtmode", discriminatorType =
9 DiscriminatorType.STRING, length = 10)
public class Payment {
10 @Id
@Column(name="payid")
11 private int id;
12 @Column(name="amount")
private int amount;
13 public int getId() {
return id;
14 }
public void setId(int id) {
15 this.id = id;
}
16 public int getAmount() {
return amount;
17
}
18 public void setAmount(int amount) {
this.amount = amount;
19 }
}
Card.java
2 import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
3 import javax.persistence.Entity;
@Entity
4 @DiscriminatorValue(value="card")
public class Card extends Payment{
5 @Column(name="cardnum")
private int cardno;
6 @Column(name="crdtype")
private String card_type;
7
public int getCardno() {
8 return cardno;
}
9 public void setCardno(int cardno) {
this.cardno = cardno;
10 }
public String getCard_type() {
11 return card_type;
}
12
public void setCard_type(String card_type) {
13 this.card_type = card_type;
}
14 }
15
Cheque.java
2 import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
3 import javax.persistence.Entity;
@Entity
4
@DiscriminatorValue(value="cheque")
5 public class Cheque extends Payment {
@Column(name="chqnum")
6 private int chequeno;
@Column(name="chqtype")
7 private String cheque_type;
public int getChequeno() {
8 return chequeno;
}
9
public void setChequeno(int chequeno) {
10 this.chequeno = chequeno;
}
11 public String getCheque_type() {
return cheque_type;
12 }
public void setCheque_type(String cheque_type) {
13 this.cheque_type = cheque_type;
}
14
}
• Create the main class that stores the object of Persistent object
In this step, we are going to create a main class (which contains the main method) that
stores the object of the persistent class.
App.java
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
session.save(p);
session.save(c);
session.save(chq);
session.getTransaction().commit();
1
import org.hibernate.Session;
2 import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
3
public class App
4 {
public static void main( String[] args )
5
{
6 Configuration cfg= new Configuration();
cfg.configure("hibernate.cfg.xml");
7 SessionFactory s= cfg.buildSessionFactory();
Session session=s.openSession();
8 session.beginTransaction();
9 Pay p=new Pay();
p.setAmount(5100);
10
19 session.getTransaction().commit();
20 System.out.println( "successfully added" );
}
21
}
22
23
• OUTPUT
• DATABASE TABLE
DISADVANTAGES
The main disadvantages of this strategy are:
• Most of the values are null in the table; hence, we cannot apply not null constraint.
• In this strategy, the table cannot be normalized, which means we cannot expand this table
into new tables or columns.
To overcome these disadvantages, we use TABLE_PER_CLASS strategy.
2 @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
3
2
import javax.persistence.Column;
3 import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
4 import javax.persistence.GenerationType;
import javax.persistence.Id;
5 import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
6 import javax.persistence.Table;
@Entity
7 @Table(name="p1")
8 @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public class Payment {
9 @Id
@GeneratedValue(strategy=GenerationType.AUTO)
10 @Column(name="payid")
private int id;
11
@Column(name="amount")
12 private int amount;
public int getId() {
13 return id;
}
14 public void setId(int id) {
this.id = id;
15 }
public int getAmount() {
16
return amount;
17 }
public void setAmount(int amount) {
18 this.amount = amount;
}
}
2 import javax.persistence.Column;
import javax.persistence.Entity;
3 import javax.persistence.Table;
@Entity
4 @Table(name="c1")
public class Card extends Payment {
5 @Column(name="cardnum")
private int cardno;
6 @Column(name="cardtype")
private String card_type;
7
public int getCardno() {
8 return cardno;
}
9 public void setCardno(int cardno) {
this.cardno = cardno;
10 }
public String getCard_type() {
11 return card_type;
}
12 public void setCard_type(String card_type) {
this.card_type = card_type;
13 }
}
14
15
16
Cheque.java
8
import javax.persistence.Column;
9 import javax.persistence.Entity;
import javax.persistence.Table;
10 @Entity
@Table(name="ch1")
11 public class Cheque extends Payment {
@Column(name="chequeno")
12
private int chequeno;
13 @Column(name="chequetype")
private String cheque_type;
14 public int getChequeno() {
return chequeno;
15 }
public void setChequeno(int chequeno) {
16 this.chequeno = chequeno;
}
17 public String getCheque_type() {
return cheque_type;
18
}
19 public void setCheque_type(String cheque_type) {
this.cheque_type = cheque_type;
20 }
}
21
22
23
24
25
2
<?xml version='1.0' encoding='UTF-8'?>
3 <!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 5.3//EN"
4 "http://hibernate.sourceforge.net/hibernate-configuration-5.3.dtd">
5 <hibernate-configuration>
<session-factory>
6
<property name="hibernate.hbm2ddl.auto">update</property>
7 <property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect
</property>
8 <property name="hibernate.connection.url">jdbc:mysql://
localhost:3306/example</property>
9 <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver
</property>
10 <property name="connection.username">root</property>
<property name="connection.password">root</property>
11
<mapping class="com.app.Concrete_Map2.Payment"></mapping>
12
<mapping class="com.app.Concrete_Map2.Card"></mapping>
13 <mapping class="com.app.Concrete_Map2.Cheque"></mapping>
14 </session-factory>
</hibernate-configuration>
3) Create the main class that stores the object of POJO object
In this step, we are going to create the main class (which contains the main method) that
stores the object of the POJO class.
App.java
1
2
import org.hibernate.Session;
3 import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
4
4. OUTPUT
5. DATABASE TABLES
payment table
card table
cheque table
2
@Inheritance(strategy=InheritanceType.JOINED)
3
2 import javax.persistence.Column;
import javax.persistence.Entity;
3 import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
4 import javax.persistence.Id;
import javax.persistence.Inheritance;
5 import javax.persistence.InheritanceType;
import javax.persistence.Table;
6
@Entity
7
@Table(name="pp")
8 @Inheritance(strategy=InheritanceType.JOINED)
public class Payment {
9
@Id
10 @GeneratedValue(strategy=GenerationType.AUTO)
@Column(name="payid")
11 private int id;
12
@Column(name="amount")
13 private double amount;
Card.java
2 import javax.persistence.Column;
import javax.persistence.Entity;
3 import javax.persistence.Table;
4
@Entity
5 @Table(name="ccd")
Cheque.java
1
import javax.persistence.Column;
2 import javax.persistence.Entity;
import javax.persistence.Table;
3
4 @Entity
@Table(name="ch")
5
public class Cheque extends Payment {
6
@Column(name="chqno")
7 private int chqno;
@Column(name="chqtype")
8 private String chq_type;
9
public int getChqno() {
return chqno;
10 }
public void setChqno(int chqno) {
11 this.chqno = chqno;
}
12 public String getChq_type() {
return chq_type;
13
}
14 public void setChq_type(String chq_type) {
this.chq_type = chq_type;
15 }
}
16
15
3) Create the main class that stores the object of POJO object
In this step, we are going to create the main class (which contains the main method) that
stores the object of the POJO class.
App.java
2 import org.hibernate.Session;
import org.hibernate.SessionFactory;
3 import org.hibernate.cfg.Configuration;
4 public class App
{
5
public static void main( String[] args )
6 {
Configuration cfg= new Configuration();
7 cfg.configure("hibernate.cfg.xml");
SessionFactory s= cfg.buildSessionFactory();
8 Session sess= s.openSession();
sess.beginTransaction();
9
Payment payment= new Payment();
10 payment.setAmount(6900);
11
20 System.out.println("successfully inserted");
}
21 } tem.out.println("successfully inserted");
}
22
}
OUTPUT
4. DATABASE TABLES
payment table
card table
cheque table
assertThat(session.createQuery("from MyProduct")
.getResultList()).hasSize(2);
}
In this example, we've created two Book and Pen objects, then queried their super-
class MyProduct to verify that we'll retrieve two objects.
Hibernate can also query interfaces or base classes which are not entities but are
extended or implemented by entity classes. Let's see a JUnit test using
our @MappedSuperclass example:
@Test
public void givenSubclasses_whenQueryMappedSuperclass_thenOk() {
MyEmployee emp = new MyEmployee(1, "john", "baeldung");
session.save(emp);
assertThat(session.createQuery(
"from com.baeldung.hibernate.pojo.inheritance.Person")
.getResultList())
.hasSize(1);
}
Note that this also works for any super-class or interface, whether it's
a @MappedSuperclass or not. The difference from a usual HQL query is that we have
to use the fully qualified name since they are not Hibernate-managed entities.
If we don't want a sub-class to be returned by this type of query, then we only need to
add the Hibernate @Polymorphism annotation to its definition, with type EXPLICIT:
@Entity
@Polymorphism(type = PolymorphismType.EXPLICIT)
public class Bag implements Item { ...}
In this case, when querying for Items, the Bag records won't be returned.
Choosing a Strategy
Choosing the right inheritance strategy is not an easy task. As so often, you have to
decide which advantages you need and which drawback you can accept for your
application. Here are a few recommendations:
• If you require the best performance and need to use polymorphic queries
and relationships, you should choose the single table strategy. But be aware,
that you can’t use not null constraints on subclass attributes which increase
the risk of data inconsistencies.
• If data consistency is more important than performance and you need
polymorphic queries and relationships, the joined strategy is probably your
best option.
• If you don’t need polymorphic queries or relationships, the table per class
strategy is most likely the best fit. It allows you to use constraints to ensure
data consistency and provides an option of polymorphic queries. But keep in
mind, that polymorphic queries are very complex for this table structure and
that you should avoid them.
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(updatable = false, nullable = false)
private Long id;
@Version
private int version;
@Column(table = "author_details")
private Category category;
...
}
That’s all you need to do to map the 2 database tables to the Author entity. Every time
you persist or update an Author entity, Hibernate writes the values of
the id, firstName, lastName, and version attributes to the author table, and the values
of the id, pseudonym, and category attributes to the author_details table.
And when you read an Author entity, Hibernate gets the attribute values from the
same 2 tables.