Hibernate - Composite Identifiers @EmbeddedId @IdClass With @GeneratedValue is impossible

요즘에, MSA 꽂혀서 이거저거 공부를 여전히 하고 있다.
그러다가 DDD 에 대해서 관심이 가게 되고,
DDD 를 공부하다가 또한 JPA 에 꽂혀서 이거저거 건드리고 있다.

그러다가 좀 fucking 한 걸 발견해서 포스팅 해보려고 한다.

DDD 에서는  Ubiquitous Language 라는 개념이 있다.

도메인 전문가와 개발자 간에 같이 공유하며, 해당 프로젝트에 참여하는 모든 사람 간에 공유되는 언어이다.

도메인 주도 설계 구현 이라는 책에서 적절한 예시를 주고 있다.

1.
patient.setShotType(ShotTypes.TYPE_FLU);
patient.setDoes(dose);
patient.setNurse(nurse);

2.
patient.giveFluShot();

3.
Vaccine vaccine = vaccines.standardAdultFluDose();

nurse.administerFluVaccine(patient, vaccine);

3가지 예시 중 어느 것이 유비쿼터스 언어를 잘 반영하고 있다고 할까?


유비쿼터스 언어에 대한 대략적인 감은 잡았을 것이라고 생각한다.


도메인 관점에서 어떻게 하면 유비쿼터스 언어를 반영하는 설계를 할 수 있을까? 라는 고민을 항상 한다.
DDD start 라는 책에서는 엔티티와 밸류 오브젝트라는 개념을 다룬다. (두 개념에 대한 설명은 하지 않겠다.)

아래 링크 참조
http://getoutsidedoor.com/2018/08/06/ddd-entities-value-objects-aggregates/

여기서, 밸류 오브젝트를 통한 식별자를 사용하는 개념이 나온다.
단순히, 어떤 엔티티를 설계할 때 단순히 식별자를 Long 혹은 String 으로 type 선언을 하게 되면,
유비쿼터스 언어를 잘 반영했다고 보기 어렵게 된다.

좀 더 도메인 관점에서 해당 도메인을 잘 나타내기 위해서는 단순히 식별자를 Long 혹은 String type을 사용하기보다, 밸류 오브젝트로 한 번 더 래핑을 하는 형식이 도메인을 더 잘 나타낼 수 있다고 생각한다.

예를 들어 Order 라는 엔티티가 있을 때 단순히
식별자를 private Long id; 혹은 private String id; 라고 하기 보다
OrderNo 라는 Type 을 사용하는 것이다.




하지만, 식별자를 래핑하여 밸류 오브젝트로 사용할 경우,, 하이버네이트에서는 더 이상 @GeneratedValue 를 사용할 수 없게 된다.

하이버네이트에서 식별자를 래핑하는 경우는 복합키를 사용 할 때이다.
예를 들어 @EmbeddedId

1
2
3
4
5
6
7
8
9
@Embeddable
public class OrderEntryPK implements Serializable {
 
    private long orderId;
    private long productId;
 
    // standard constructor, getters, setters
    // equals() and hashCode()
}

1
2
3
4
5
6
7
8
@Entity
public class OrderEntry {
 
    @EmbeddedId
    private OrderEntryPK entryId;
 
    // ...
}

혹은 @IdClass

1
2
3
4
5
6
7
8
9
10
@Entity
@IdClass(OrderEntryPK.class)
public class OrderEntry {
    @Id
    private long orderId;
    @Id
    private long productId;
     
    // ...
}

참고
https://www.baeldung.com/hibernate-identifiers

@GeneratedValue 를 사용하여 allocationSize 속성을 이용하여 캐싱 설정을 할 수 있어
성능에 많은 이점이 있다.

하지만 밸류 오브젝트로 래핑하는 순간 복합키로 인식되어,
Hibernate 에서 @GeneratedValue 를 있어도 무시해버린다.

먼저 @EmbeddedId 테스트 이다.
Author 라는 엔티티에 AuthorId 라는 밸류 식별자를 가진다.


아래와 같이 테스트 코드 작성 시

아래와 같이 null id generated 라는 예외를 던진다. Long type이 generate 될지라도, AuthorId 객체가 생성 되지 않는것 같다.



다음은 @IdClass 테스트 이다. 테스트 코드는 위와 동일하다.


역시 또한 AuthorId 가 null 이다... 쉿


그래서 커뮤니티를 뒤져봤다. 아래와 같이 같이 사용이 불가능 하다고 한다..




참고 하길 바라며,, 혹시 이 포스팅이 틀렸다면, 댓글로 바로 잡아주시길 바랍니다.

댓글

이 블로그의 인기 게시물

About JVM Warm up

About idempotent

About Kafka Basic

About ZGC

sneak peek jitpack

Spring Boot Actuator readiness, liveness probes on k8s

About Websocket minimize data size and data transfer cost on cloud

About G1 GC

대학생 코딩 과제 대행 java, python, oracle 네 번째