본문 바로가기
Today I Learned 2024. 7. 3.

(24.07.03)[12주차] QueryDSL사용을 위한 Repository 분리

QueryDSL로 JPA에서 쿼리문을 구현하려고 했지만, 기존에 JpaRepository 를 상속받는 Repository를 사용하고 있었기에 내부에 QueryDSL 쿼리역시 구현을 할 수 없었다.

 

그렇다고 Service단에서 그 쿼리를 구현하는 것은 계층을 분리하고자 하는 의의와 벗어나게 되는데,

 

그렇다면 어떻게 QueryDSL을 사용할 수 있을지에 대한 구조 정리


QueryDSL을 사용하기 위한 Repository 구성

  • JpaRepository만 상속 받는 형태의 Repository로 Service 계층에서 findBy save delete 등의 쿼리 메서드를 사용할 수 있었지만, QueryDSL을 사용하기 위해서는 이 상속받고 있는 Repository를 사용하는 것이 아닌 위의 그래프처럼 Custom Repository를 만들어 줘야한다.
  • 해당 구성은 실제로 사용되는 구조
    • interface의 특징을 잘 알고 있으면 사용할 수 있듯이 정상적으로 사용되는 부분인 만큼 기억을 할 수 있도록해야한다.

Custom Repository 생성

public interface LikeJpaRepository {

    Optional<Like> findByApartIdAndUser(Long apartId, User user);
...
  • 위의 코드를 예시로 좋아요 기능을 위한 좋아요 엔터티의 LikeRepository가 있을 경우에 QueryDSL로 구현을 해야하는 메서드들을 모은 interface인 Custom Repository를 생성
    • ○○○RepositoryCustom 이라고 통상적으로 사용하지만, 여러 Repository가 있는 상황에서 좀더 Repository가 명확하게 어떤 Repository인지 확실히 하기 위해서 ○○○JpaRepository 로 임의로 정했음

구현 RepositoryImpl 생성

public class LikeRepositoryImpl implements LikeJpaRepository {

...
    private final JPAQueryFactory jpaQueryFactory;
...

    @Override
    public Optional<Like> findByApartIdAndUser(Long apartId, User user) {

        Like like = jpaQueryFactory.selectFrom(qLike)
                .where(qLike.apart.id.eq(apartId).and(qLike.user.userName.eq(user.getUserName())))
                .fetchOne();

        return Optional.ofNullable(like);
    }
...

 

  • ○○○JpaRepository 에 Service에서 사용할 메서드를 추가가 되었다면, interface이므로 이를 구현시켜줄 Impl 클래스를 생성해서 구현
  • implements ○○○JpaRepository  를 하고 @Override를 통해 QueryDSL 을 사용해서 해당 메서드의 기능을 구현
    • interface의 반드시 구현되어야하는 특징을 해결하기 위한 클래스라고 생각하면 편함

기존 Repository에 구현

public interface LikeRepository extends JpaRepository<Like, Long>, LikeJpaRepository{
...
  • interface끼리는 서로 다중 상속이 가능하므로 extends를 사용해서 쓸 수 있음
    • 따라서, Service에서 LikeRepository를 주입받아 likeRepository.findByApartIdAndUser 처럼 사용할 수 있고, 이는 LikeRepositoryImpl에서 QueryDSL로 구현된 메서드를 사용할 수 있는 것

계층 분리의 장점 정리

테스트 용이성

  • Service단에서 QueryDSL을 직접 구현을 해버리면 해당 쿼리를 검증하는데 Serivce의 단위테스트에서 진행을 해야될지 또는 통합으로 Slice Test로 진행을 해야할지 구분하기 매우 애매해진다.
    • QueryDSL 자체는 DB에 직접 접속해서 작업을 처리하는 단게이므로 Repository 계층에 맞기 때문에
  • 따라서, 테스트 작성에서도 단순화 시키면서 복잡한 쿼리를 따로 검증할 수 있는 용이성이 있음

유지보수성

  • QueryDSL도 Repository에 사용하기 위해 분리함으로써 Service는 Repository단의 오류나 기능작동 즉, QueryDSL에서의 오류를 담당하지 않기 때문에 Repository단에서만 해당 이슈를 해결할 수 있음

재사용성

  • QueryDSL도 query단위로 재사용할 수 있지만, 그 통째로 구현되는 QueryDSL 로 구성된 메서드도 Repository주입을 통해서 여러 서비스 단에서 공통적으로 사용할 수도 있음

계층을 분리를 하는 것을 알고 있었지만, 

 

Repository를 여러개를 만들경우에는 interface를 사용해서 여러개를 상속 extends 할 수 있는 방향으로 진행을 해도 크게 문제가 되는 포인트가 없다는 것을 이번 학습을 통해서 알았기에

 

필요가 있다면, 위 코드드들을 참고해서 바로 쓸 수 있도록 해야할 것.