jpa에서 복합키(pk가 여러 개)를 가진 테이블을 정의하려면, 키(이하 pk)들을 따로 뺀 클래스(이하 pk 클래스)를 별도로 정의하고 entity 클래스로 가져와야 한다.
이에 대한 구현은 각각 @EmbeddedId, @IdClass를 활용한 2가지로 할 수 있다.
결론부터 말하자면 두 방법이 본질적으로는 차이가 없으나 구현하는 방법과 사용하는 방법이 다르니 편한 것으로 선택하면 된다.
@EmbeddedId
- pk클래스에 **@**Embeddable 어노테이션을 지정해줘야 한다.
- pk클래스를 Serializable 인터페이스로 구현해야 한다.
- pk클래스에 대한 기본 생성자가 필요하다 - build.gradle.kts에서 kotlin-jpa 플러그인 혹은 kotlin-noarg 플러그인을 추가했다면 @EmbeddedId 어노테이션을 붙이면 자동으로 기본 생성자가 만들어진다.
- pk클래스가 public 클래스여야 함
pk 클래스와, entity 구현
@Entity
@Table(name = "person")
class Person(
@EmbeddedId
val personPk: PersonPk,
@Column(name = "created_at")
val createdAt: LocalDateTime,
)
@Embeddable
data class PersonPk(
@Column(name = "name")
val name: String,
@Column(name = "phone_number")
val phoneNumber: String,
) : Serializable
사용 방법
interface PersonRepository : JpaRepository<Person, PersonPk>
val findAll: List<Person> = PersonRepository.findAll()
val person = Person("juhi", "82012341")
val findById: Person? = PersonRepository.findById(person).orElse(null)
// pk 중 한 값에 접근하고 싶을 때
// pk테이블을 호출하고 -> 내부 컬럼을 호출할 수 있다.
val name = findById?.personPk.name
키 컬럼에 바로 접근하지 못한다.
@IdClass
- pk클래스에 대한 별도 어노테이션은 필요 없다.
- pk클래스를 Serializable 인터페이스로 구현해야 한다.
- pk클래스에 대한 기본 생성자가 필요하다
- pk클래스가 public 클래스여야 한다.
- entity 클래스에 pk클래스의 프로퍼티들을 id로 다시 한 번 정의해야 한다.
- entity 클래스에 @IdClass로 pk 클래스를 지정해야 한다
pk 클래스와, entity 구현
@Entity
@Table(name = "person")
@IdClass(PersonPk::class)
class Person(
@Id
@Column(name = "name")
val name: String,
@Id
@Column(name = "phone_number")
val phoneNumber: String,
@Column(name = "created_at")
val createdAt: LocalDateTime,
)
data class PersonPk(
val name: String? = null,
val phoneNumber: String? = null,,
) : Serializable
pk클래스에 대하여 기본 생성자가 필요하기 때문에 기본값으로 null을 지정해줬다. (별도로 붙이는 어노테이션이 없기 때문에 자동으로 기본 생성자가 만들어지지 않는다.)
사용 방법
interface PersonRepository : JpaRepository<Person, PersonPk>
val findAll: List<Person> = PersonRepository.findAll()
val person = Person("juhi", "82012341")
val findById: Person? = PersonRepository.findById(person).orElse(null)
// pk 중 한 값에 접근하고 싶을 때 해당 컬럼에 바로 접근할 수 있다.
val name = findById?.name
키 컬럼에 바로 접근할 수 있다.
차이점
- 물리적인 모델 관점에서 차이점은 없다.
- EmbeddedId는 결합된 pk클래스 자체가 의미 있을 때, 이를 분명하게 전달할 수 있다.
- IdClass는 데이터의 각 키에 접근하는 일이 많을 경우 유용하다.
반응형
'서버 > SpringBoot' 카테고리의 다른 글
스프링부트가 다중 유저 요청을 처리하는 방법 (Thread Pool, Thread Safe) (0) | 2022.11.25 |
---|---|
[Spring/Kotlin] Entity는 data class로 구현하는게 좋을까? (0) | 2022.05.15 |
[Spring] 하나의 build.gradle 파일로 여러 내부 프로젝트 빌드하기 (0) | 2022.03.31 |
@RequestBody로 지정한 객체에 꼭 기본 생성자가 필요할까? (com.fasterxml.jackson.databind.exc.InvalidDefinitionException) (2) | 2022.01.05 |
[Spring] EHcache를 이용해 캐시 간단하게 적용하기 (feat. @ Cacheable) (0) | 2022.01.05 |