The inheritance is one of the most scenarios that can be encountered once we’ve been coming into business field. Inside the Java Persistence API (JPA) The entities support inheritance, polymorphic, polymorphic associations, and polymorphic queries. Both abstract and concrete classes can be entities, and both of them can be annotated with the @Entity annotation, mapped as entities and queried for as entities.
Entities can extend non-entity classes and non-entity classes can extend entity classes, so you will find samples for entities classes inherit from a non-entity classes and non-classes entities inherit from entities classes. The purpose of this tutorial is to cover the inheritance in an entity class hierarchy; which means that the super class and its sub classes will be marked as entities.
The Mapping of class hierarchies has different implementation techniques, that’s depends on the Java Persistence API (JPA) vendor. It is important to know that this tutorial consider the EclipseLink – JPA as a JPA provider, so be sure that you are willing enough to use the EclipseLink.(See EclipseLink Maven Installation and EclipseLink Installation).
To implement an inheritance you’ve different implementations that might be used:
Single Table Inheritance Strategy:
In the single table inheritance, the entire hierarchy is represented by a single table, in that the entity of super class defines set of mapped states and the entity of subclass inherits most of its mapped states from its super class entity.The discriminator column (TYPE) is added to the table to distinguish between the stored instances. That’s column will determine what class in the hierarchy the stored object belongs to. Also, additional columns will be added into that table for those newly defined attributes in the sub classes entities.
Joined Table Inheritance Strategy:
In the joined table inheritance, each class shares data from the root table. In addition, each subclass defines its own table that adds its extended state. Where the shared data is stored in a single table while the newly defined fields are stored in separate table.
Table per Concrete Strategy:
This strategy is an optional, based on the specification “Support for the table per concrete class inheritance mapping strategy is optional”. In table per class inheritance a table is defined for each concrete class in the inheritance hierarchy to store all the attributes of that class and all of its super classes.
At this tutorial, we will cover the Table Per Concrete Strategy for achieving the inheritance mapping, the next coming tutorial shall cover other strategies.
Anatomy of Inheritance Hierarchy (Classes Design)
Let’s assume an inheritance hierarchy, in that Project entity represents the root of it and set of entities inherit the Project like GlobalProject and LocalProject entities.
Let’s see a class design for the suggested inheritance relationship at the Figure 1.1:
Figure 1.1
Based on the design of classes that shown in the Figure 1.1, you’ve seen a different inheritance relationships achieved between both of Employee and Developer from a side and Project, GlobalProject and LocalProject from a different side.
This time we’re using the Table Per Concrete Strategy rather using of Joined Strategy as you’ve seen before in the Joined Inheritance tutorial.
Anatomy of Database Design
Table per class inheritance allows inheritance to be used in the object model, when it doesn’t exist at the data model. In table per class inheritance, a table is defined for each concrete class in the hierarchy to store all attributes of that class and all of its super classes. We’ve changed the design of the Project entity and its sub classes for enabling the Table Per Concrete philosophy or strategy, so see the Figures 1.2,1.3 and 1.4 that shows you the final form of suggested tables.
Figure 1.2
Figure 1.3
Figure 1.4
- Each entity is mapped to a separate table.
- All properties of the entity, including inherited properties are mapped to columns of the table for the entity.
How Should The Project, GlobalProject and LocalProject Looks Like?
The following snippet of code must shows you a proper clarification for the final form of the Project, GlobalProject and LocalProject entities respectively.
Project.java
// The final form of Project entity that required for applying the Table Per Concrete package net.javabeat.eclipselink.data; import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; import javax.persistence.ManyToMany; @Entity(name="Project") @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public class Project { @Id private int projectId; private String projectName; @ManyToMany(mappedBy="projects",cascade=CascadeType.ALL) private List<Employee> employees; public int getProjectId() { return projectId; } public void setProjectId(int projectId) { this.projectId = projectId; } public String getProjectName() { return projectName; } public void setProjectName(String projectName) { this.projectName = projectName; } public List<Employee> getEmployees() { return employees; } public void setEmployees(List<Employee> employees) { this.employees = employees; } }
GlobalProject.java
// The final form of GlobalProject entity that required for applying the Table Per Concrete package net.javabeat.eclipselink.data; import java.math.BigDecimal; import javax.persistence.Entity; @Entity public class GlobalProject extends Project { private String projectCountry; private BigDecimal projectBudget; public String getProjectCountry() { return projectCountry; } public void setProjectCountry(String projectCountry) { this.projectCountry = projectCountry; } public BigDecimal getProjectBudget() { return projectBudget; } public void setProjectBudget(BigDecimal projectBudget) { this.projectBudget = projectBudget; } }
LocalProject.java
// The final form of LocalProject entity that required for applying the Table Per Concrete package net.javabeat.eclipselink.data; import java.math.BigDecimal; import javax.persistence.Entity; @Entity public class LocalProject extends Project { private BigDecimal projectBudget; public BigDecimal getProjectBudget() { return projectBudget; } public void setProjectBudget(BigDecimal projectBudget) { this.projectBudget = projectBudget; } }
- The Project class represents the root of the inheritance tree.
- The Project class should contains the @Inheritance annotation.
- Unlike the Single Table Inheritance and the Join Inheritance strategies, the Table Per Concrete uses the strategy of TABLE_PER_CLASS inside the @Inheritance annotation.
- There is no @DiscriminatorColumn annotation used. Neither the root of the inheritance hierarchy nor the sub classes does provide such that annotation.
- There is no @DiscriminatorValue annotation used. Neither the root of the inheritance hierarchy nor the sub classes does provide such that annotation.
- If you’ve remembered that ManyToMany relationship between Employee and Project that discussed previously, you are almost remembering the JoinTable that already used for achieving such that relation. Now for a proper use of the Table Per Concrete Strategy, you have to remove the constraint that had been used for referencing the ProjectId column that located at the Project Table from the Employee_Project JoinTable. If you didn’t remove that constraint, you are about getting an exception tells you that the records of Project sub classes cannot be inserted into your database.
Persistence Configuration Required
We need no any change that could happen at the Persistence Configuration (persistence.xml). So you could use the previous one that’s used in the Join Inheritance.
Executable Application
Use the same executable application mentioned at Join Inheritance for achieving the persistence operation. it should work properly, cause nothing changed at the executable class.
Database Persisted Records
If you’ve noticed the persisted records using Single Table Strategy, you can notice that by every persisted record at the database, you have one record and only one. But when you’ve used the Join Inheritance Strategy, you can notice that by every persisted record at the database, we have one record at the Root of the hierarchy (Super Class) and another record represents the entity itself (Subclass). Now look at the Figures 1.5, 1.6 and 1.7 that show you the persisted records when we are considering the Table Per Concrete.
Figure 1.5
Figure 1.6
Figure 1.7
Summary
This tutorial covers the @Inheritance annotation and its used for achieving an inheritance relationship. Already we’ve established a Project entity and both of GlobalProject and LocalProject inherit it. When you are coming into inheritance, you have multiple choices to implement it. One of the major strategies that could be used is a Table Per Concrete Strategy which in all classes in the hierarchy persisted in their own tables. The main difference between the Joined Strategy & Table Per Concrete is the Table per concrete doesn’t consider any previous records that could be inserted into the Super class Table, while the Join Inheritance consider it.