#04장 Repo와 모델 구현 (JPA 중심)
최범균 저「DDD START!, 2016」를 읽고 정리하였습니다.
다룰 내용
JPA 이용 리포 구현
엔티티와 밸류 매핑
밸류 컬렉션 매핑
애그리거트 로딩 전략과 영속성 전파
식별자 생성 기능
JPA 이용 리포 구현
JPA: 도메인 모델과 리포 구현시 선호되는 기술 (ORM 기반)
가능한, 리포 구현 클래스를 infra 영역에 위치 시켜 의존성을 낮춰야
기본 구현 방법
ID로 애그 조회
public Order findById(OrderNo no){ em.find(Order.class, no); }애그 저장
public void save(Order order){ em.persist(order); }삭제
// 고객이 요구해도, 보통 바로 삭제는 안함 (관리자가 삭제한 데이터도 조회해야될때도 있으니) public void remove(Order order) { entityManager.remove(order); }
트랜잭션 예시
명명 규칙: findBy 뒤에 조건 (e.g., findByOrdererld())
ID 외로 agg 조회시 Criteria나 JPQL 사용
매핑
애그와 JPA 매핑을 위한 기본 규칙
agg 루트는 엔티티이므로 @Entity로 매핑 설정
한 테이블에 엔티티와 밸류가 공존시
밸류 는 @Embeddable로 설정
밸류 는 @Embedded로 설정
다이어그램을 보고, 코드로 확인해보자.
사례: 주문 (엔티티), 주문자(밸류), 배송지정보(밸류) → 주문 내역서 (purchase_order) 테이블에 다 포함
@Entity
@Embeddable, @Embedded
JPA 2 부터 @Embeddable은 중첩 허용해서, 아래 처럼, Shippinglnfo 안에 Address랑 Receiver 포함
기본 생성자
필드 접근 방식 사용
엔티티를 객체가 제공할 기능 중심으로 구현하도록 유도하면, JPA 매핑 처리를 프로퍼티 방식이 아닌 필드방식으로 선택해서, 불필요한 get/set메서드를 구현하지 말아야 한다.
AttributeConverter를 이용한 밸류 매핑 처리
밸류 타입의 프로퍼티를 한개 컬럼에 매핑해야될때가 있다. (e.g. DB에 1000mm 저장)
AttributeConverter: 밸류 타입과 칼럼 데이터 간의 변환 처리를 해준다.
밸류 컬렉션: 별도 테이블 매핑
밸류 컬렉션 별도 테이블로 매핑할때는 @ElementCollection과 @CollectionTable 사용
밸류 컬렉션: 한개 컬럼 매핑
사례: 도메인 모델에서 이메일을 Set으로 보관하고, DB에서는 한컬럼에 콤마로 구분해서 저장할때
AttributeConverter 사용 하기
밸류를 이용한 아이디 매핑
식별자 대게 String이나 Long
근데, 밸류타입을 식별자로 지정하려면, @Id대신 @EmbeddedId 사용
위와 같이 사용해서 장점은, 주문번호가 1세대 2세대가 있다면, OrderNo 안에서 구분짓게 할 수 있다.
별도 테이블에 저장하는 밸류 매핑
상품 화면에 리뷰가 있다고 리뷰가 상품 애그리거트에 포함되있는게 아니다. 서로의 변경이 영향을 주지 않기에, 리뷰는 엔티티가 맞지만 상품 애그리거트에 속한 것은 아니다.
밸류인지 애그리거트인지 구별 방법: 고유식별자 갖는지 확인하면 된다. 다만, DB에 넣기 위한 ID 식별자와 헷갈리지 말자.
예, Aritcle(엔티티) - ArticleContent(밸류타입)
밸류를 매핑한 테이블 지정은 @SecondaryTable와 @AttributeOverrides 사용
밸류 컬렉션을 @Entity로 매핑하기
개념적으로 밸류인데 기술 제약으로 엔티티로 사용해야 될때가 있다.
예를 들어, 상속 구조를 갖는 밸류 타입을 사용하면, @Embeddable대신 @Entity 사용
아래 Image는 엔티티로 선언된다. 다만, 사실상 밸류임으로 상태 변경하는 기능은 추가하지 않는다.
Image의 라이프사이클은 Product에 달려있다. (orphanRemoval true로 사용)
ID 참조와 조인 테이블을 이용한 단방향 M:N 매핑
애그리거트 간 집합 연관은 피해야하지만, 그렇게 하는 것이 유리하다면, ID 참조를 이용한 단방향 집합 연관을 적용할 수 있다.
애그리거트 로딩 전략
JPA 매핑을 설정시, 애그리거트에 속한 객체가 모두 모여야 완전한 하나가 된다는 것을 알아두자.
속한 모든 객체가 완전한 상태여야 함을 의미한다.
조회 시점에서 애그리거트를 완전한 상태가 되도록 하려면 → FetchType.EAGER
하지만 항상 좋은것은 아니다. 책에선 카타시안 조인 나타나는 문제를 보여준다.
애그리거트의 영속성 전파
완전한 하나라는 것은, 조회 뿐만아니라 저장하고 삭제할 때도 하나로 처리
저장/삭제시, 루트뿐만 아니라 속한 모든 객체 저장/삭제하기
Cascade 사용
식별자 생성 기능
방법
사용자가 직접 생성 (e.g., 이메일)
도메인 로직으로 생성
DB 일련번호 사용
엔티티가 식별자 생성 기능을 제공하는 것보다는 별도 서비스로 식별자 생성 기능을 분리해야 한다.
식별자 생성의 적합한 또 다른 장소는 리포지터리이다.
Last updated