HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
📝
남득윤 학습 저장소
/
도메인 주도 개발 시작하기
도메인 주도 개발 시작하기
/
4️⃣
4장 리포지터리와 모델 구현
4️⃣

4장 리포지터리와 모델 구현

4.1 JPA를 이용한 리포지터리 구현

4.1.1 모듈 위치

  • 리포지터리 인터페이스는 애그리거트와 같이 도메인 영역에 위치
  • 기술로 리포지터리를 구현한 클래스는 인프라스트럭처 영역에 속한다.
 

4.1.2 리포지터리 기본 기능 구현

  • E findById(ID id);
  • E save(E entity);
 

4.2 스프링 데이터 JPA를 이용한 리포지터리 구현

@Entity public class Order { @Id @GeneratedValue private Long id; } public class OrderRepository extends JpaRepository<Order, Long>{ }
 
스프링 데이터 JPA는 OrderRepository를 리포지터리로 인식해서 알맞게 구현한 객체를 스프링 빈으로 등록한다.

4.3 매핑 구현

4.3.1 엔티티와 밸류 기본 매핑 구현

  • 애그리거트 루트
    • @Entity
  • 밸류
    • @Embeddable
    • 다른 엔티티 혹은 밸류에서 프로퍼티로 사용될 때는 @Embedded
    • @Embedded 사용시 대상 밸류의 내부 프로퍼티와 다른 column name을 가지게 하고 싶다면 @AttributeOverride 애너테이션을 사용한다.
 

4.3.2 기본 생성자

  • JPA에서 @Entity와 @Embeddable로 클래스를 매핑하려면 protected/ public 기본 생성자를 제공해야 한다.

4.3.3 필드 접근 방식 사용

  • JPA 프로바이더가 객체 생성을 위해 기본 생성자를 호출 한뒤 매핑을 처리하는 방식에는 두가지 방식이 있다.
    • @Access(AccessType.FIELD) 필드 방식
    • @Access(AccessType.PROPERTY)메서드 방식 (getter/setter)
      • 게터 세터 필요
  • 필드 접근 방식을 사용하자
    • 세터를 요구한다는 점이 설계에 치명적이다.
 
  • 기본적으로 @Id /@EmbeddedId의 위치에 따라 매핑 처리 방식을 자동으로 결정한다.

4.3.4 AttributeConberter를 이용한 밸류 매핑 처리

@Converter(autoApply = true) public class OpenTypeConverter implements AttributeConverter<OpenType, Byte> { @Override public Byte convertToDatabaseColumn(final OpenType attribute) { return attribute.getCode(); } @Override public OpenType convertToEntityAttribute(final Byte dbData) { return Stream.of(OpenType.values()) .filter(ot -> ot.getCode() == dbData) .findFirst() .orElseThrow(IllegalStateException::new); } }
db 관점에서는 <<Value>> OpenType을 숫자로 처리 했을때 이점이 있어서 Byte (TinyInt)로 저장 하게 하였다.
 

4.3.5 밸류 컬렉션: 별도 테이블 매핑

@ElementCollection +@CollectionTable을 함께 사용한다.
  • 대상 컬렉션을 List로 선언하면 하이버네이트는 순서를 표현하기 위한 index column을 자동으로 생성해준다.

4.3.6 밸류 컬렉션: 한개 칼럼 매핑

AttributeConvert를 이용해 한개의 칼럼에 매핑할 수 도 있다.
 

4.3.7 밸류를 이용한 ID 매핑

  • 식별자라는 의미를 부각
  • 식별자에 로직을 넣을 수 있다.
 

4.3.8 별도 테이블에 저장하는 밸류 매핑

  • 애그리거트에서 루트 엔티티를 뺀 나머지 요소는 대부분 밸류이다.
 

4.3.9 밸류 컬렉션을 @Entity로 매핑하기

  • @Embedabble에는 상속을 적용할 수 없다.
  • @Entity와 @Embeddable은 컬렉션의 clear() 메서드 호출시 발생하는 쿼리가 다르다.
  • 코드 유지 보수와 성능 두 가지 측면을 잘 고려해야한다.
 

4.3.10 ID 참조와 조인 테이블을 이용한 단방향 M-N 매핑

3장에서 애그리거트 간 집합 연관 (toMany)은 성능 상의 이유로 피해야 한다고 했다. toMany를 정말 양방향으로 설정하고 싶다면 Id 집합을 조인 테이블 거는것을 고려하자
 
이때 사용할 수 있는 JPA의 구현 방식이
@ElementCollection 과 @CollectionTable 이다.
@Entity public class Bookmark extends BaseIdEntity { private String link; @Embedded private TagIds tagIds; } @Embeddable public class TagIds{ @ElementCollection @CollectionTable( name = "bookmark_tag", joinColumns = @JoinColumn(name = "bookmark_id"), uniqueConstraints = @UniqueConstraint(columnNames = {"bookmark_id", "tag_id"}) ) @Column(name = "tag_id") private Set<Long> values = new HashSet<>(); }
bookmark 도메인
생성 테이블 구조
id
link
1
www.naver.com
 
bookmark_id
tag_id
1
2
1
3
id 참조를 이용해 북마크 도메인에서는 태그 도메인에 대한 참조를 끊을 수 있다.
북마크 조회시 태그를 함께 조회해야 하는 경우 tag_id 까지만 조회하고 tag_id를 tag로 변환하는 책임은 태그 도메인에 위임 할 수 있다.
 

 

4.4 애그리거트 로딩 전략

애그리거트에 속한 객체가 모두 모여야 완전한 애그리거트 루트 하나를 이룰 수 있다. 즉 findById를 이용해 조회한 애그리거트 루트는 완전한 상태여야 한다.
Bookmark bookmark = bookmarkRepository.findById(id);
개발자는 조회한 북마크로 내부의 태그 id 집합 과 같은 모든 객체를 참조할 수 있을 것을 기대한다.
 
이를 위해 조회 방식을 EAGER 로 설정 할 수 있다. EAGER 로딩을 통해 루트 엔티티를 조회하면 하이버네이트는 연관된 데이터 조회를 위해 join 쿼리를 발생시킨다. 한 쿼리에서 join 문이 여러개 걸쳐지는 경우 애플리케이션에 로딩되는 메모리가 필요 이상으로 과다해 질 수 있다.
 
조회 방식을 LAZY로 설정하는 경우 한 트랜잭션 (요청)에 대해서 쿼리 실행 횟수가 많아질 가능성이 더 높다.
 
일장일단이 있으므로 애그리거트 및 발생 쿼리를 고려하여 로딩 전략을 선택하여야 한다.

4.5 애그리거트의 영속성 전파

위에서 언급한 애그리거트 루트의 조회 뿐만 아니라 저장/삭제에 따른 영속성 처리 역시 애그리거트의 내부에서는 한 덩어리로 이루어 져야 한다.
@Embeddable 매핑은 함께 저장되고 삭제되므로 cascade 속성을 추가로 설정하지 않아도 된다. 반면 애그리거트에 속한 @Entity 타입에 대한 매핑은 cascade 속성을 사용해 저장,삭제 시에 함께 처리되도록 설정해야한다.
 

4.6 식별자 생성 기능

  • 사용자가 직접 생성 (e.g. 이메일)
  • 도메인 로직으로 생성 (e.g. timestamp + uuid)
    • 도메인서비스/리포지터리에 규칙을 위치 시킴
  • db seqence (e.g. oracle sequence/ mysql auto increment)
 

4.7 도메인 구현과 DIP

  • 도메인 구현의 편의를 위해 DIP를 위반할 수 있다.
  • jpa에 대한 의존, spring에 대한 의존을 도메인에 남기면 개발 속도를 크게 높일 수 있다.
  • 저울질을 잘 해서 의식적으로 선택하자