Engineering Full Stack Apps with Java and JavaScript
In the SINGLE_TABLE strategy, hibernate will create a single table for all the classes in an inheritance hierarchy. There will be a discriminator column that tells us the class to which that row belongs.
In this example, we will create and save three entity classes – Shape, Rectangle and Circle; where Rectangle and Circle extends from Shape.
If you are not following the tutorials in order, refer to the article http://javajee.com/your-first-hibernate-43-program for the basic setup including hibernate configuration file.
You should replace the user class in the configuration file with Shape, Rectangle and Circle classes as:
<!-- Names the annotated entity class -->
<mapping class="com.javajee.hiberex.dto.Shape"/>
<mapping class="com.javajee.hiberex.dto.Rectangle"/>
<mapping class="com.javajee.hiberex.dto.Circle"/>
Else you will get org.hibernate.MappingException: Unknown entity:…
The base entity class, shape will have id and fillcolor properties:
@Entity
public class Shape {
@Id @GeneratedValue
int shapeId;
String fillcolor;
//Getters and setters not shown here; create them manually or generate in eclipse.
}
Entity class Rectangle extends from Shape, and have length and breadth properties:
@Entity
public class Rectangle extends Shape{
long length;
long breadth;
//Getters and setters not shown here; create them manually or generate in eclipse.
}
Entity class Circle extends from Shape, and has one property radius:
@Entity
public class Circle extends Shape{
long radius;
//Getters and setters not shown here; create them manually or generate in eclipse.
}
Now use the below test class to create objects for these classes, populate data and save them:
public class ShapeTest {
public static void main(String[] args) {
Shape s = new Shape();
s.setFillcolor("Green");
Rectangle r = new Rectangle();
r.setBreadth(4);
r.setLength(6);
Circle c = new Circle();
c.setRadius(5);
Configuration configuration = new Configuration();
configuration.configure();
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
.applySettings(configuration.getProperties()).build();SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(s);
session.save(r);
session.save(c);
session.getTransaction().commit();
}
}
When you execute the above test class, below queries are executed by hibernate (as seen from the console):
Hibernate: insert into Shape (fillcolor, DTYPE) values (?, 'Shape')
Hibernate: insert into Shape (fillcolor, breadth, length, DTYPE) values (?, ?, ?, 'Rectangle')
Hibernate: insert into Shape (fillcolor, radius, DTYPE) values (?, ?, 'Circle')
You can see that only one table, Shape is created and all data is being inserted into the same table.
From the above queries, we can find the columns of the Shape table: fillcolor, DTYPE, breadth, length, radius. Columns for all classes in the inheritance hierarchy will be present in the table, even if it is not used by other classes.
Things will be more clear, once you see the database snapshot. Just do a select all query (select * from Shape). There will be only a single table. The DTYPE column is the discriminator and has values Shape, Rectangle or Circle to denote to which class each row belongs.
If a field (or column) is not applicable for a particular class, it will have null values for that class.
This behavior is known as SINGLE_TABLE strategy, and is the default inheritance behavior in hibernate if we don’t specify a different strategy using the @Inheritance annotation.
You can also explicitly specify SINGLE_TABLE strategy using the @Inheritance annotation:
@Entity
@Inheritance (strategy = InheritanceType.SINGLE_TABLE)
public class Shape {
…
If you execute the code after placing @Inheritance annotation with strategy as SINGLE_TABLE, you will get the same behavior as above.
You can however use another annotation @DescriminatorValue to specify a different name than the class name for the discriminator column (DTYPE) value:
Shape
@Entity
@Inheritance (strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("SH")
public class Shape {
…
Rectangle
@Entity
@DiscriminatorValue("RE")
public class Rectangle extends Shape{
…
Circle
@Entity
@DiscriminatorValue("CI")
public class Circle extends Shape{
…
Verifying results with @DiscriminatorValue
If you execute the same test class, you will see the below queries generated by hibernate:
Hibernate: insert into Shape (fillcolor, DTYPE) values (?, 'SH')
Hibernate: insert into Shape (fillcolor, breadth, length, DTYPE) values (?, ?, ?, 'RE')
Hibernate: insert into Shape (fillcolor, radius, DTYPE) values (?, ?, 'CI')
You can also change the discriminator column name using @DiscriminatorColumn annotation as:
@Entity
@Inheritance (strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("SH")
@DiscriminatorColumn (name="DISC_COL")
public class Shape {
…
Vwrifying the results with @DiscriminatorColumn annotation
If you execute the same test class, you will now see the below queries generated by hibernate:
Hibernate: insert into Shape (fillcolor, DISC_COL) values (?, 'SH')
Hibernate: insert into Shape (fillcolor, breadth, length, DISC_COL) values (?, ?, ?, 'RE')
Hibernate: insert into Shape (fillcolor, radius, DISC_COL) values (?, ?, 'CI')
Single table strategy is the least normalized strategy. Other two strategies are TABLE_PER_CLASS and JOINED.