ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 도메인 주도 개발 시작하기 CH.4 ~ CH.5
    DESIGN PATTERN & ARCHITECTURE 2024. 6. 19. 23:53

     

     

     

     

    Ch. 4 :  레포지토리와 모델 구현 

     

     

    4.1.

    • 레포지터리 인터페이스 
      • 애그리거트와 같이 도메인 영역에 속함 
      • 인터페이스는 애그리거트 루트를 기준으로 작성해야 함
    • 레포지터리 구현 클래스 
      • 인프라스트럭처 영역에 속함 
      • 인프라스트럭처에 대한 의존을 낮춰야 함 
    • 레포지터리의 기본 기능 
      • ID로 애그리거트 조회 
        • ID외의 다른 조건으로 애그리거트를 조회할 때에는 JPA의 Criteria나 JPQL을 사용할 수 있음 
      • 애그리거트 저장 
        • JPA를 사용한다면 트랜잭션 범위에서 변경한 데이터는 자동 저장되므로 저장하는 메서드를 추가할 필요가 없음 
      • 삭제 기능의 경우 삭제 요구사항이 있더라도 데이터 조회가 필요한 경우나 원복해야하는 경우도 있기 때문에 데이터를 실제로 삭제하는 경우가 많지 않음 

     

    4.2

    • 스프링 데이터 JPA
      • 레포지터리 인터페이스를 정의하면 레포지터리 구현 객체를 알아서 만들어 스프링 빈으로 등록해줌 
      • 지정한 규칙에 맞게 메서드를 작성해야 함 

    4.3

    • 애그리거트 루트는 엔티티 이므로 @Entity로 매핑 설정 
    • 밸류는 @Embddable 로 매핑 설정 
      • 밸류 타입 프로퍼티는 @Embedded로 매핑 설정 
    • @Embeddable과 @Entity로 매핑하려면 기본 생성자를 제공해야 함 
      • 기본 생성자는 JPA 프로바이더가 객체를 생성할 때만 사용할 수 있게 protected로 선언 
    • 필드 접근 방식 
      • JPA는 필드와 메서드 두가지 방식으로 매핑 처리 가능 
        • 메서드 방식 
          • 프로퍼티를 위한 get/set 메서드 구현 필요
            • 도메인의 의도가 사라지고 객체가 아닌 데이터 기반으로 엔테테 구현의 가능성이 높아짐 
            • 밸류를 불변타입으로 구현하려면 set 메서드 자체가 필요없는데, JPA 구현 방식 때문에 공개 set 메서드를 추가하게 됨 
          • => 객체가 제공할 기능 중심으로 엔티티를 구현하게끔 유도하기 위해 JPA 매핑 처리를 프로퍼티 방식이 아닌 필드 방식으로 선택해서 불필요한 get/set 메서드를 구현하지 말아야 함 
      • JPA 구현체인 하이버네이트는 @Access를 통해서 명시적으로 접근방식을 지정하지 않으면, @Id나 @EmbeddedId가 어디에 위치했냐에 따라 접근 방식을 선택함
        • @Id나 @EmbeddedId가 필드에 위치하면 필드 접근 방식, get 에 위치하면 메서드 접근 방식
    • AtributeConverter
      • 두개 이상의 프로퍼리를 가진 밸류 타입을 한개 컬럼에 매핑
      • @Converter의 authApply 속성의 기본값은 false
        • false이면 프로퍼티 값을 변환할 때 사용할 컨버터를 직접 지정해야 함 
    • @ElementCollection, @CollectionTable
      • 밸류컬렉션을 저장하는 별도 테이블을, 컬렉션이 속할 엔티티 외부 키를 이용해서 엔티티에 해당하는 테이블을 참조하도록 함 
      • 리스트 타입 자체가 인덱스를 가지고 잊기 때문에, 인덱스를 저장하기 위한 프로퍼티가 없음 
        • @OrderColumn 애노테이션을 이용해서 지정한 칼럼에 리스트의 인덱스 값 저장 
      • @CollectionTable
        • 밸류를 저장할 테이블 지정 
      • 밸류컬렉션이 별도 테이블이 아닌 한개 컬럼에 저장하는 경우 AtrribudeConverter 사용 
    • 밸류 타입의 식별자 
      • 밸류타입을 식별자로 매핑하면 @Id 대신 @EmbeddedId 애노테이션을 사용 
      • 식별자는 Serializable 타입이어야 하므로 밸류 타입은 Serializable 인터페이스를 상속 받아야 함 
      • 밸류타입으로 식별자를 구현하면 식별자에 기능추가가 가능해짐 
      • JPA는 내부적으로 엔티티 비교 목적의 equals(), hashcode() 사용하므로 식별자로 사용할 때 밸류 타입은 이 메서드를 알맞게 구현해야 함 
    • 루트 엔티티 외에 또다른 엔티티가 한 애그리거트에 있다면, 진짜 엔티티 인지, 다른 애그리거트는 아닌지 의심해야함 
      • 밸류와 엔티티의 구분 방법 = 식별자 
        • 매핑되는 테이블의 식별자 != 애그리거트 구성요소의 식별자 
        • 데이터를 연결하기 위한 식별자와 구분해야 함 
    • 밸류를 별도의 테이블에 저장하고 매핑한 테이블을 지정하기 위해 @SecondaryTable과 @AttributeOverride를 사용할 수 있음 
      • @SecondaryTable을 이용하면 두 테이블을 조인해서 데이터를 조회하게 됨을 유의 
    • 밸류 컬렉션의 Entity 매핑 (계층 구조의 밸류 타입)  
      • @Embeddable 타입의 클래스 상속 매핑을 지원하지 않음 
        • @Entity를 이용해서 상속 매핑으로 처리해야 함 
          • 한 테이블에 하위 클래스 매핑 
            • 상위 테이블
              • @Inheritance (InheritanceType.strategy = SINGLE_TABLE)
              • @DiscriminatorColumn 애너테이션으로 타입 구분용 칼럼 지정 
            • 하위 테이블
              • @DiscriminatorValue로 매핑 설정 
      •  하이버 네이트는 @Embeddable타입의 컬렉션의 clear()메서드 호출시 컬렉션에 속한 객체를 로딩하지 않고, 한번에 delete 쿼리로 삭제 처리 수행 
        • 애그리거트 특성을 유지하면서 문제해소를 위해 상속을 포기하고 embeddable 매핑 단일 클래스가 낫다 
    • ID 참조와 조인 테이블을 통한 단방향 M-N 매핑 
      • @ElementCollection, @CollectionTable 사용 
        • ElementCollection은 삭제할 때 매핑에 사용한 조인 테이블의 데이터도 함께 삭제 

     

    4.4

    • 애그리거트 
      • 속한 객체가 모두 모여야 완전한 하나가 됨 
        • 조회 시점에 완전한 애그리거트 상태를 위해 연관 매핑 조회 방식을 즉시 로딩으로 설정할 수 있음 
        • 하지만 조회 성능 이슈로 검토가 필요함 
        • 애그리거트는 개념적으로 하나여야 하지만, 루트 엔티티를 로딩하는 시점에 모두 로딩해야 하는 것은 아님 
        • 애그리거트에 맞게 즉시 로딩과 지연로딩을 선택 

     

    4.5 

    • 저장 매서드는 애그리거트 루트만 저장하면 안되고 애그리거트에 속한 모든 객체를 저장해야 함 
    • 삭제 메서드는 애그리거트 루트뿐 아니라 애그리거트에 속한 모든 객체를 삭제해야 함 
      • @Embeddable 매핑 타입은 함께 저장되고 삭제됨 
      • 엔티티 매핑의 경우 cascade 속성을 사용 

     

    4.6

    • 식별자 생성 
      • 사용자 직접 할당 
      • 도메인 로직 할당
        • 도메인이나 레포지토리에 구현 
      • DB의 일련번호 사용 
        • ex) JPA 의 경우 저장 이후에 엔티티 식별자 사용 가능 

     

    4.7

    • 도메인 구현과 DIP
      • 리포지토리와 도메인 모델의 구현 기술은 거의 바뀌지 않으므로 애그리거트, 레포지터리등 도메인 모델 구현시에 타협이 가능함 

     

     

     

     

    Ch. 5 :  스프링 데이터 JPA를 이용한 조회 기능 

     

    5.1 

    • CQRS
      • 명령 모델(레포지토리)과 조회 모델(DAO)을 분리 
        • 도메인 모델을 명령모델로 주로 사용됨 

     

    5.2

    • 검색 조건 Specification 
      • agg 파라미터 
        • 검사 대상이되는 객체 
        • 레포지토리에 사용시 애그리거트 루트, DAO에 사용시 검색 결과로 리턴할 데이터 객체 
      • 실제 스펙은 사용하는 기술에 맞춰 구현 

     

    5.3

     

    • JPA 정적 메타 모델 
      • @StaticMetaModel 애너테이션을 이용해서 관련 모델 지정 
      • 오타등의 문제 발생을 방지 
      • 대신에, 문자열로 프로퍼티 지정도 가능 
    • 스펙 구현 클래스를 생성하거나 별도 클래스에 스펙 생성 기능을 모을 수도 있음

     

    5.4

    • findAll() 메서드는 스펙 인터페이스를 파라미터로 가짐 

     

    5.5

    • 스펙 조합 
      • and
      • or
      • not
      • where

     

    5.6

    • 정렬 지정 
      • 메서드 이름에 OrderBy를 사용해서 정렬 기준 지정 
      • 메서드에 Sort를 인자로 전달 

    5.7

    • 페이징 처리 
      • Pageable 타입 사용 
        • PageRequest 클래스를 이용해 생성 
          • sort로 정렬순서도 지정 가능 
        • 프로퍼티를 비교하는 findBy프로퍼티 형식의 메서드는 Pageable 타입을 사용하더라도 리턴 타입이 List면 count 쿼리를 실행하지 않는다. 
          • => 반환 타입을 Page으로 지정한 경우에 추가 count 쿼리가 발생
            • 단, 스펙을 사용하는 findAll 메서드에 Pageable 타입을 사용하면 리턴 타입이 Page가 아니어도 count 쿼리가 실행됨
          • 페이징 처리와 관련된 정보가 필요 없다면 리턴타입을 List로 받아 불필요한 count 쿼리를 실행하지 않도록 해야함 
          • 스펙을 사용하고 페이징 처리를 하면서 count 쿼리는 실행하고 싶지 않다면, 스프링 테이터 JPA가 제공하는 커스텀 레포지토리 기능을 이용해서 직접 구현해야 함 

    5.8 

    • 스펙 빌더 클래스 
      • if와 각 스펙을 조합하는 코드에서 실수하지 않도록 방지 

    5.9

    • 동적 인스턴스 생성 
      • JPQL의 동적 인스턴스 사용 
        • new 키워드 
          • 생성할 인스턴스의 완전한 클래스 이름을 지정하고 괄호 안에 생성자에 인자로 전달할 값을 지정 
          • 이때, 조회 전용 모델을 사용할 수 있음 
        • JPQL을 그대로 사용하므로 객체 기준으로 쿼리를 작성하면서도 동시에 지연/즉시 로딩과 같은 고민 없이 원하는 모습으로 데이터 조회 가능 
    • 조회 전용 모델
      • 표현 영역을 통해 사용자에게 데이터 보여줌 

     

    5.10

    • 하이버네이트 @Subselect, @Immutable, @Synchronize 
      • @Subselect
        • 쿼리 결과를 @Entity로 매핑 가능
        • 조회 쿼리를 값으로 가짐 
        • 쿼리 실행 결과를 매핑할 테이블 처럼 사용 
        • 해당 어노테이션을 조회한 @Entity역시 수정할 수 없음 
          • 수정하려고 하면 예외가 발생 
        • @Subselect의 값으로 지정한 쿼리를 from 절의 서브 쿼리로 사용 
          • 이를 사용하고 싶지 않다면 별도의 mapper 구현 필요 
      • @Immutable 
        • 하이버네이트가 해당 엔티티의 매핑 필드 / 프로퍼티가 변경되어도 DB에 반영하지 않고 무시 
      • @Synchronize
        • 해당 엔티티와 관련된 테이블 목록을 명시 
        • 하이버네이트가 엔티티를 로딩하기 전에 지정한 테이블과 관련된 변경이 발생하면 플러시를 먼저 진행 

     

     

Designed by Tistory.