Spring Boot + JPA: 복합 기본키(@EmbeddedId) 중 특정 컬럼으로 조회하기

 

Spring Boot + JPA: 복합 기본키(@EmbeddedId) 중 특정 컬럼으로 조회하기

Spring Boot + JPA: 복합 기본키(@EmbeddedId) 중 특정 컬럼으로 조회하기

Spring Boot와 JPA를 활용하면서 복합 기본키(Composite Primary Key)를 사용하는 경우가 있습니다. 특히 @EmbeddedId를 사용하는 상황에서, 복합 기본키 중 특정 컬럼만 조건으로 조회하고 싶을 때 구현 방법을 알아보겠습니다. 이 글은 해당 문제를 해결하기 위해 필요한 모든 과정을 자세히 다룹니다.



1. 복합 기본키와 @EmbeddedId

복합 기본키는 테이블의 기본키가 두 개 이상의 컬럼으로 이루어진 경우를 말합니다. JPA에서는 복합 기본키를 @EmbeddedId 또는 @IdClass를 이용해 매핑할 수 있습니다. 이 글에서는 @EmbeddedId를 사용하는 방법을 기준으로 설명합니다.

복합 키 클래스 정의

먼저, 복합 기본키를 나타내는 클래스를 정의해야 합니다. 이 클래스는 반드시 @Embeddable 어노테이션으로 선언해야 하며, Serializable 인터페이스를 구현해야 합니다.

import jakarta.persistence.Embeddable;
import java.io.Serializable;
import java.util.Objects;

@Embeddable
public class CompositeKey implements Serializable {

    private String convsId;
    private String anotherId;

    // 기본 생성자
    public CompositeKey() {}

    // 생성자
    public CompositeKey(String convsId, String anotherId) {
        this.convsId = convsId;
        this.anotherId = anotherId;
    }

    // Getter/Setter
    public String getConvsId() {
        return convsId;
    }

    public void setConvsId(String convsId) {
        this.convsId = convsId;
    }

    public String getAnotherId() {
        return anotherId;
    }

    public void setAnotherId(String anotherId) {
        this.anotherId = anotherId;
    }

    // equals & hashCode 재정의
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        CompositeKey that = (CompositeKey) o;
        return Objects.equals(convsId, that.convsId) && Objects.equals(anotherId, that.anotherId);
    }

    @Override
    public int hashCode() {
        return Objects.hash(convsId, anotherId);
    }
}


엔티티 클래스 정의

복합 키를 사용하는 엔티티 클래스는 @EmbeddedId를 사용해 복합 키를 참조합니다.

import jakarta.persistence.*;

@Entity
public class MyEntity {

    @EmbeddedId
    private CompositeKey id;

    private String someData;

    // 기본 생성자
    public MyEntity() {}

    // 생성자
    public MyEntity(CompositeKey id, String someData) {
        this.id = id;
        this.someData = someData;
    }

    // Getter/Setter
    public CompositeKey getId() {
        return id;
    }

    public void setId(CompositeKey id) {
        this.id = id;
    }

    public String getSomeData() {
        return someData;
    }

    public void setSomeData(String someData) {
        this.someData = someData;
    }
}


2. 복합 키 컬럼 중 특정 컬럼으로 조회하기

@EmbeddedId를 사용하는 경우, 복합 키의 특정 컬럼만을 조건으로 조회하려면 다음과 같은 방법을 사용할 수 있습니다.


방법 1: JPQL 사용

JPQL에서 복합 키의 특정 필드에 접근하려면 경로 탐색을 활용해야 합니다.

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import java.util.List;

public interface MyEntityRepository extends CrudRepository<MyEntity, CompositeKey> {

    @Query("SELECT e FROM MyEntity e WHERE e.id.convsId = :convsId")
    List<MyEntity> findByConvsId(String convsId);
}

사용 예

@Autowired
private MyEntityRepository myEntityRepository;

public void testQuery() {
    String convsId = "12345";
    List<MyEntity> results = myEntityRepository.findByConvsId(convsId);
    results.forEach(System.out::println);
}


방법 2: Criteria API 사용

Criteria API를 사용하면 동적으로 쿼리를 생성할 수 있습니다.

import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.*;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public class MyEntityCriteriaRepository {

    @PersistenceContext
    private EntityManager entityManager;

    public List<MyEntity> findByConvsId(String convsId) {
        CriteriaBuilder cb = entityManager.getCriteriaBuilder();
        CriteriaQuery<MyEntity> query = cb.createQuery(MyEntity.class);
        Root<MyEntity> root = query.from(MyEntity.class);

        // 복합 키의 convsId 조건 설정
        Predicate condition = cb.equal(root.get("id").get("convsId"), convsId);
        query.where(condition);

        return entityManager.createQuery(query).getResultList();
    }
}

사용 예

@Autowired
private MyEntityCriteriaRepository criteriaRepository;

public void testCriteria() {
    String convsId = "12345";
    List<MyEntity> results = criteriaRepository.findByConvsId(convsId);
    results.forEach(System.out::println);
}

방법 3: Example 사용

Spring Data JPA의 Example 객체를 사용하면 간단한 조회 조건을 설정할 수 있습니다.

import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.repository.CrudRepository;

public interface MyEntityRepository extends CrudRepository<MyEntity, CompositeKey> {
    List<MyEntity> findAll(Example<MyEntity> example);
}

사용 예

@Autowired
private MyEntityRepository myEntityRepository;

public void testExample() {
    CompositeKey key = new CompositeKey();
    key.setConvsId("12345");

    MyEntity probe = new MyEntity();
    probe.setId(key);

    ExampleMatcher matcher = ExampleMatcher.matching()
            .withMatcher("id.convsId", ExampleMatcher.GenericPropertyMatchers.exact());

    Example<MyEntity> example = Example.of(probe, matcher);
    List<MyEntity> results = myEntityRepository.findAll(example);
    results.forEach(System.out::println);
}


3. 어떤 방법을 선택할까?

  • 간단한 조회: 특정 조건만으로 조회하려면 JPQL을 사용하는 것이 가장 간단합니다.
  • 동적 조건 추가: 여러 조건을 조합하거나 동적으로 조건을 설정하려면 Criteria API를 사용하는 것이 유리합니다.
  • 간단한 예제 기반 조회: 조건이 간단하고 데이터가 샘플 형태로 준비되어 있다면 Example을 사용하는 것도 좋은 선택입니다.


요약

  • @EmbeddedId를 사용하는 경우, 복합 기본키 중 특정 필드 조건만으로 조회하려면 JPQL, Criteria API, 또는 Example 객체를 활용할 수 있습니다.
  • 사용 사례에 따라 적합한 방법을 선택하세요.

이 글이 복합 키를 사용하는 JPA 프로젝트를 개발할 때 도움이 되길 바랍니다. 추가적인 질문이 있다면 댓글로 남겨주세요!

Comments