Spring Boot @IdClass Example

1. Introduction

In this tutorial, we will learn how to implement composite primary keys in a Spring Boot application using the @IdClass annotation. This approach is useful when you want to define a composite key using more than one field without creating an embedded class.

Key Points

1. @IdClass is used to specify a composite primary key class for an entity.

2. This primary key class must be public and have a Serializable interface.

3. Each field in the primary key class must correspond to a field in the entity class.

4. The @Id annotation is used in the entity class on each field that is part of the composite key.

2. Implementation Steps

1. Create the primary key class.

2. Define the entity class with @Id annotations on the fields that are part of the composite key.

3. Configure the repository interface.

4. Implement a simple CRUD operation to test the functionality.

3. Implementation Example

// Step 1: Create the primary key class
public class EmployeeId implements Serializable {
    private Long departmentId;
    private Long employeeId;

    // Default constructor
    public EmployeeId() {}

    // Constructor with parameters
    public EmployeeId(Long departmentId, Long employeeId) {
        this.departmentId = departmentId;
        this.employeeId = employeeId;
    }

    // Getters and Setters
    public Long getDepartmentId() { return departmentId; }
    public void setDepartmentId(Long departmentId) { this.departmentId = departmentId; }
    public Long getEmployeeId() { return employeeId; }
    public void setEmployeeId(Long employeeId) { this.employeeId = employeeId; }

    // hashCode and equals implementations
    @Override
    public int hashCode() {
        return Objects.hash(departmentId, employeeId);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        EmployeeId that = (EmployeeId) o;
        return Objects.equals(departmentId, that.departmentId) &&
               Objects.equals(employeeId, that.employeeId);
    }
}

// Step 2: Define the entity class
@Entity
@IdClass(EmployeeId.class)
public class Employee {
    @Id
    private Long departmentId;
    @Id
    private Long employeeId;

    private String name;

    // Constructors, Getters, Setters
}

// Step 3: Configure the repository interface
public interface EmployeeRepository extends JpaRepository<Employee, EmployeeId> {
}

// Step 4: Implement a simple CRUD operation (assuming a Spring Boot controller or service)
@RestController
public class EmployeeController {
    @Autowired
    private EmployeeRepository repository;

    @PostMapping("/employees")
    public Employee addEmployee(@RequestBody Employee employee) {
        return repository.save(employee);
    }

    @GetMapping("/employees/{departmentId}/{employeeId}")
    public Employee getEmployee(@PathVariable Long departmentId, @PathVariable Long employeeId) {
        return repository.findById(new EmployeeId(departmentId, employeeId))
                         .orElseThrow(() -> new NotFoundException("Employee not found"));
    }
}

Explanation:

1. EmployeeId class is defined with fields departmentId and employeeId, both of which are used to represent the composite key.

2. The Employee entity class is annotated with @IdClass(EmployeeId.class), linking it to the composite key class.

3. Each field that is part of the composite key in the Employee class is annotated with @Id.

4. The EmployeeRepository extends JpaRepository, utilizing EmployeeId as the ID type, which allows leveraging Spring Data JPA functionalities.

5. A simple REST controller is created to demonstrate the basic CRUD operations using the composite key.

Comments