[Spring] QueryDSL transform을 사용하는 이유?

Walter Mitty·2023년 6월 15일
4

부모 Entity인 Faq가 자식 Entity인 FaqImage를 List로 가지고 있을 때, Faq를 조회할 때 FaqImage를 프론트에 어떻게 보내줄까?

| 가장 간단하게는 JPA 사용시 연관관계를 이용하는 방법이다.

  1. faqRespository.findByFaqId(faqId)로 faq 객체를 한번 찾고,
  2. faqImageRepository.findAllByFaqId(faqId) 를 찾아서
  3. Response 객체에 담아주는 방법도 있을것이다.

그러나 그러면 불필요하게 select 구문이 두번 날아가는 것을 확인할 수 있을 것이다.
그러면 네이티브 쿼리로 직접 join 구문을 명시해둬서 가져오기? 그러면 JPA를 사용하는 이유가 떨어질 것이다.

QueryDSL 사용하기

| 1안 (비추천)

DTO

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FaqDTO {

    private Integer faqId; // 고유 번호
    private Integer adminId; // 작성한 관리자 고유 번호
    private String faqTitle; // 제목
    private String faqContent; // 내용
    // 아래부턴 자식 Entity 내용들
    private Integer imageId;
    private String imageUrl;
    private Integer sort;
}

FaqCustomRepositoryImpl

@Override
    public List<FaqDTO> findFaqInfo(Integer faqId) {

        List<FaqDTO> result = queryFactory
        .select(Projections.constructor(FaqDTO.class,
                faq.faqId, faq.adminId, faq.faqTitle, faq.faqContent, faqImage.id, faqImage.faqFileUrl, faqImage.sort))
        .from(faq)
        .leftJoin(faqImage).on(faq.faqId.eq(faqImage.faq.faqId))
        .where(faq.faqId.eq(faqId))
        .orderBy(faqImage.sort.asc())
        .fetch();

        return result;
    }

이런식으로 QueryDSL를 짜줘도 문제는 없다! 연관관계가 맺어져있어서 알아서 잘 찾아오기 때문. 단지 문제는... 👇

.select(Projections.constructor(FaqDTO.class,시에 자식 객체를 자동으로 List로 변환해주지 않는다. 그말은 즉 !
아래처럼 부모 객체 하나 조회시 자식 객체 개수 만큼, 자식 객체 하나에 부모객체가 늘 같이 불러온다는 뜻이다. 프론트 입장에서는....중복되는 데이터들에 짜증날 것 같다. 또한 Json이 길어지면 그만큼 속도나 네트워크 비용에서도 문제가 있겠지...?

| 2안 (추천)

DTO

@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FaqDTO {

    private Integer faqId; // 고유 번호
    private Integer adminId; // 작성한 관리자 고유 번호
    private String faqTitle; // 제목
    private String faqContent; // 내용
    private List<FaqImageDTO> faqImagesUrl; // 이미지 URL
}

FaqCustomRepositoryImpl

@Override
    public List<FaqDTO> findFaqInfo(Integer faqId) {

		List<FaqDTO> result = queryFactory
            .selectFrom(faq)
            .leftJoin(faqImage).on(faq.faqId.eq(faqImage.faq.faqId))
            .where(faq.faqId.eq(faqId))
            .orderBy(faqImage.sort.asc())
            .transform(groupBy(faq.faqId).list(Projections.constructor(FaqDTO.class,
                faq.faqId, faq.adminId, faq.faqTitle, faq.faqContent,
                list(Projections.constructor(FaqImageDTO.class, faqImage.id, faqImage.faqFileUrl, faqImage.sort)
            ))));

        return result;
    }

이런식으로.transform(groupBy(faq.faqId).list( 이용해주면 부모객체 하나에 자식객체를 리스트로 붙여서 반환할 수 있다.

여기서 주의!!! 안에 listimport static com.querydsl.core.group.GroupBy.list; 를 임포트 해서 써줘야 한다 : )


1개의 댓글

아주 멋지십니다~

답글 달기