서버/SpringBoot
[kotlin] spring jpa에서 복합키를 사용하는 방법, @EmbeddedId, @IdClass
juhi
2022. 5. 10. 18:28
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는 데이터의 각 키에 접근하는 일이 많을 경우 유용하다.
반응형