Mapping Table per Concrete Class in JPA

In object-oriented programming, inheritance allows you to create hierarchies of related classes. When mapping these class hierarchies to a relational database using the Java Persistence API (JPA), you have different strategies available. One such strategy is the Table per Concrete Class strategy.

Overview

The Table per Concrete Class strategy, also known as “Single Table Inheritance,” involves creating a separate table for each concrete class in the hierarchy. Each table contains only the fields specific to that class, with no shared superclass table.

In this tutorial, we’ll explore how to use the Table per Concrete Class strategy with JPA. We’ll cover the steps involved in mapping the class hierarchy to database tables and performing CRUD operations.

Prerequisites

To follow along with this tutorial, you’ll need the following:

  • Basic knowledge of Java and JPA
  • A Java development environment (IDE)
  • A relational database supported by your JPA implementation (e.g., MySQL, PostgreSQL)

Step 1: Set up the Project

  1. Create a new Java project in your preferred IDE.
  2. Add the required dependencies to your project’s build file (e.g., Maven or Gradle) for JPA implementation (e.g., Hibernate) and the database driver.

Step 2: Define the Class Hierarchy

For this tutorial, let’s assume we have a class hierarchy representing different types of employees: Employee (base class), Manager (subclass), and Developer (subclass).

Create the following Java classes:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    private String name;

    // Getters and setters
}

@Entity
public class Manager extends Employee {
    private String department;

    // Getters and setters
}

@Entity
public class Developer extends Employee {
    private String programmingLanguage;

    // Getters and setters
}

In the Employee class, note the @Inheritance annotation with the InheritanceType.TABLE_PER_CLASS strategy. This specifies that the Table per Concrete Class strategy should be used for mapping the class hierarchy.

Here is an overview of the above Classes:

Mapping Table per Concrete Class in JPA

Step 3: Execute CRUD Operations

Now that you have set up the class hierarchy and configured the persistence, you can perform CRUD operations using the Table per Concrete Class strategy.

Insert records: Create instances of the concrete classes and persist them to the database:

Employee employee = new Employee();
employee.setName("John Doe");

Manager manager = new Manager();
manager.setName("Jane Smith");
manager.setDepartment("Sales");

Developer developer = new Developer();
developer.setName("Alex Johnson");
developer.setProgrammingLanguage("Java");

em.getTransaction().begin();
em.persist(employee);
em.persist(manager);
em.persist(developer);
em.getTransaction().commit();

Retrieve records: Query the database to retrieve the records:

List<Employee> employees = em.createQuery("SELECT e FROM Employee e", Employee.class).getResultList();

for (Employee emp : employees) {
    System.out.println("Name: " + emp.getName());
    
    if (emp instanceof Manager) {
        Manager mgr = (Manager) emp;
        System.out.println("Department: " + mgr.getDepartment());
    } else if (emp instanceof Developer) {
        Developer dev = (Developer) emp;
        System.out.println("Programming Language: " + dev.getProgrammingLanguage());
    }
}

Update and delete records: You can update or delete records in a similar manner.

Employee employee = em.find(Employee.class, 1L);
employee.setName("Updated Name");

em.getTransaction().begin();
em.remove(employee);
em.getTransaction().commit();

Conclusion

In this tutorial, you learned how to use the Table per Concrete Class strategy with JPA. You saw how to define a class hierarchy, configure persistence, and perform CRUD operations using the entities in the hierarchy.

The Table per Concrete Class strategy provides a straightforward way to map class hierarchies to database tables, allowing you to leverage inheritance in your application design while maintaining a clear and efficient database schema.