Repository Layer에서 2개의 도메인을 Boundary Context로서 묶기

TopOfTheHead·2026년 5월 13일

Spring JPA

목록 보기
9/10

동일한 생명주기를 갖는 도메인 2개를 분리하고 작업 시 Sevice Layer에서 2개의 Repository의존해야하는 단점이 존재
OrderOrderItem 도메인의 경우, 서로 공통된 생명주기를 가져 서비스 계층에서 서로 참조해야하는 빈도가 많다.
▶ 다음처럼 OrderService에서 2개의 Repository의존해야하는 상황이 발생.

@Service
@RequiredArgsConstructor
public class OrderService {
    private final DataJpaOrdersRepository dataJpaOrdersRepository;
    private final DataJpaOrderItemRepository dataJpaOrderItemRepository;
    //
}

▶ 해결방법의 경우 파사드 패턴 / Boundary Context를 구성한 해결방법이 존재하며, 본 글에서는 Boundary Context를 통한 해결을 수행

Order RepositoryOrderItem RepositoryBoundary Context로서 병합한 단일 Repository의존하도록 설정
OrderOrderItem을 둘다 Boundary Context로 취급하여 Repository Layer에서 하나의 도메인으로 병합

Service Layer에서는 Boundary Context로 구성된 하나의 도메인의존할 수 있는 장점이 존재.
▶ 한 Service Layer에서 복수의 Repository의존하지 않아도 된다.

  • Boundary Context 인터페이스 생성
    。해당 인터페이스 내에는 Order 도메인OrderItem 도메인Repository Layer 관련 기능을 공통적으로 작성

    。각 OrderOrderItem 도메인에서 JpaRepository<>를 확장한 기능을 가지므로, JpaRepository<>를 확장하지 않아도 된다.
@Repository
public interface OrderRepository {
  	// Order 도메인 관련
    Orders saveOrders(Orders order);
  	// OrderItem 도메인 관련
    OrderItem saveOrderItems(OrderItem orderItem);
  // ...
}
  • Boundary Context 인터페이스 구현체 생성
    。각각의 도메인Repository의존성 주입하여 각 Repository의 기능을 사용하도록 설정
    OrderOrderItem을 하나의 Boundary Context로서 병합하여 통합 관리

    BoundaryContext 구현체 생성 시 해당 구현체의존성 주입
@Repository
@RequiredArgsConstructor
public class DataJpaOrderRepositoryCombine implements OrderRepository {
  //
    private final DataJpaOrdersRepository dataJpaOrdersRepository;
    private final DataJpaOrderItemRepository dataJpaOrderItemRepository;
  // Order 도메인 관련
    @Override
    public Orders saveOrders(Orders order) {
        return dataJpaOrdersRepository.save(order);
    }
  // OrderItem 도메인 관련
  	@Override
    public OrderItem saveOrderItems(OrderItem orderItem){
        return dataJpaOrderItemRepository.save(orderItem);
    }
}
  • Service Layer 작성
    。오직 하나의 Boundary Context 역할Repository의존하면서 Order 도메인OrderItem 도메인Repository 기능을 사용
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class OrderService {
    private final OrderRepository orderRepository;
    //
    @Transactional(readOnly = false)
    public Orders saveOrders(Orders orders){
        return orderRepository.saveOrders(orders);
    }
    //
    @Transactional(readOnly = false)
    public OrderItem saveOrderItems(OrderItem orderitem){
        return orderRepository.saveOrderItems(orderitem);
    }
}

QueryDSL 활용 시 Repository Layer도메인 묶기
OrderOrderItem병합Boundary Context도메인을 정의한 Repository에 추가로 동적쿼리를 작성하기 위한 JPAQueryFactory의존성 주입하여 활용

QueryDSLJPQL을 생성하는 기능으로서 읽기 작업에서만 유용
쓰기 작업의 구현을 위해 EntityManager 객체를 추가하여 한 Repository읽기 / 쓰기 작업을 모두 구현.

。이를 통해 Service Layer는 해당 Repository의존하면서 Order / OrderItem 관련 DAO 로직QueryDSL을 사용 가능

  • 인터페이스 정의
public interface QueryDslOrderRepository{
    Orders savedOrder(Orders order);
    OrderItem saveOrderItem(OrderItem orderItem);
    List<Orders> findAllOrderByQueryDsl();
}
  • 구현체 정의
@Slf4j
@Repository
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class QueryDslOrderRepositoryImpl implements QueryDslOrderRepository{
    //
    private final JPAQueryFactory queryFactory;
	//
    private DataJpaOrdersRepository dataJpaOrdersRepository;
    private DataJpaOrderItemRepository dataJpaOrderItemRepository;
	//
    private final QOrders qOrders = QOrders.orders;
    private final QOrderItem qOrderItem = QOrderItem.orderItem;
	//
    @Transactional(readOnly = false)
    public Orders savedOrder(Orders order){
        return dataJpaOrdersRepository.save(order);
    }
    //
	@Transactional(readOnly = false)
    public OrderItem saveOrderItem(OrderItem orderItem){
        return dataJpaOrderItemRepository.save(orderItem);
    }
    public List<Orders> findAllOrderByQueryDsl(){
        return queryFactory.selectFrom(qOrders)
                .fetch();
    }
}

조회 작업의 경우 JPQL / QueryDSL로 구현하고, 쓰기 작업의 경우 다른 Repository에서 JpaRepository에서 기본 구현된 EntityManager를 활용한 삽입 / 수정 / 삭제 메서드를 활용

profile
공부기록 블로그

0개의 댓글