February 28th, 2023
JPA Inheritance Hierarchies and Mapping

SINGLE_TABLE inheritance

Single_Table – With Inheritance, all the classes are mapped to single table.
It is the default strategy.
One Employee table showing entries of PartTime and FullTime employees.


Benefits:,

High performance, but lots of null data, issues of data integrity.

				
					@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "Employee_Type")
public abstract class Employee {
				
			

TABLE_PER_CLASS inheritance

Table_Per_Class – creates table per concrete entity class.
Table for each of PartTime and FullTime employees.

 :

Benefits:

High performance, but lots of duplicate data as multiple fields are common between the tables.

				
					@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Employee {
				
			

JOINED inheritance

Join – Will create table per each entity.
3 Table each of Employee, PartTime and FullTime employees.

 

Join query result:

1.SELECT * FROM EMPLOYEE , PART_TIME_EMPLOYEE where PART_TIME_EMPLOYEE.ID = EMPLOYEE.ID

2. SELECT * FROM EMPLOYEE , FULL_TIME_EMPLOYEE where FULL_TIME_EMPLOYEE.ID = EMPLOYEE.ID

Benefits:

Performance not best as it has to join multiple tables, but good in terms of database design as there is no duplication of columns

				
					@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Employee {
				
			

Complete source

				
					spring.datasource.url=jdbc:h2:mem:testdb;NON_KEYWORDS=USER;DB_CLOSE_ON_EXIT=FALSE
spring.h2.console.enabled=true
spring.jpa.defer-datasource-initialization=true

# Turn Statistics ON
#spring.jpa.properties.hibernate.generate_statistics=true
logging.level.org.hibernate.stat=debug
#logging.level.root=trace
# Show all queries
spring.jpa.show-sql=true

# Format the queries
spring.jpa.properties.hibernate.format_sql=true
				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo.entity;

import jakarta.persistence.Column;
import jakarta.persistence.DiscriminatorColumn;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Inheritance;
import jakarta.persistence.InheritanceType;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@Data
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@RequiredArgsConstructor
@AllArgsConstructor
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Employee {
	
	@Id
	@GeneratedValue
	private Long id;
	
	@NonNull
	@Column(nullable = false)
	private String name;
}

				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo.entity;

import java.math.BigDecimal;

import jakarta.persistence.Entity;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor
@AllArgsConstructor
public class FullTimeEmployee extends Employee {

	private BigDecimal salary;
	
	public FullTimeEmployee(String name, BigDecimal salary) {
		super(name);
		this.salary = salary;
	}
}

				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo.entity;

import java.math.BigDecimal;

import jakarta.persistence.Entity;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor
@AllArgsConstructor
public class PartTimeEmployee extends Employee {

	private BigDecimal hourlyWage;
	
	public PartTimeEmployee(String name, BigDecimal hourlyWage) {
		super(name);
		this.hourlyWage = hourlyWage;
	}
}

				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo.repository;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.brains.jpa.hibernate.jpahibernatedemo.entity.Employee;

import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import jakarta.persistence.TypedQuery;
import jakarta.transaction.Transactional;

@Repository
@Transactional
public class EmployeeRepository {

	private Logger logger = LoggerFactory.getLogger(getClass());
	
	@Autowired
	EntityManager em;
	
	public void insertEmployee(Employee employee) {
		em.persist(employee);
	}
	
	public List<Employee> retrieveAllEmployee(){
		TypedQuery<Employee> query = em.createQuery("select e from Employee e", Employee.class);
		return query.getResultList();
	}
}

				
			
				
					package com.brains.jpa.hibernate.jpahibernatedemo;

import java.math.BigDecimal;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import com.brains.jpa.hibernate.jpahibernatedemo.entity.FullTimeEmployee;
import com.brains.jpa.hibernate.jpahibernatedemo.entity.PartTimeEmployee;
import com.brains.jpa.hibernate.jpahibernatedemo.repository.EmployeeRepository;

@SpringBootApplication
public class JpaHibernateDemoApplication implements CommandLineRunner {

	public static void main(String[] args) {
		SpringApplication.run(JpaHibernateDemoApplication.class, args);
	}

	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@Autowired
	private EmployeeRepository employeeRepository;
	
	@Override
	public void run(String... args) throws Exception {
		
		employeeRepository.insertEmployee(new FullTimeEmployee("Jack", new BigDecimal(10000)));
		employeeRepository.insertEmployee(new PartTimeEmployee("Jill", new BigDecimal(50)));
		logger.info("All employees: -> {}", employeeRepository.retrieveAllEmployee());
	}
}
				
			
				
					All employees: -> [Employee(id=1, name=Jack), Employee(id=2, name=Jill)]

				
			

Related Tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *