• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    해결됨

Querydsl 조회 시, DTO 필드를 List로 받는 방법을 알고 싶습니다.

24.02.29 01:32 작성 24.02.29 01:37 수정 조회수 351

0

안녕하세요.

Querydsl 학습 중에 궁금한 점이 있어서 질문드립니다.

 

Projection을 이용해서 조회 데이터를 DTO에 반환 받고 싶습니다.

하지만, DTO 필드에 List 타입이 정의되어 있습니다.

이런 경우에는 어떤식으로 데이터를 조회할 수 있는지 궁금합니다.

 

또한, 현업에서는 이런 형태의 데이터를 조회하기 위해서 어떤 방식으로 하는지 궁금합니다.

  1. 객체 그래프 탐색을 이용한 Lazy 조회 후, 로직에서 조건 필터링 ?

  2. 각 조건에 맞는 쿼리 여러번 호출 ?

  3. DTO Projection을 이용한 한방 쿼리 ?

  4. 다른 방식 ?

 

조회 데이터를 반환 받기 위한 ProductDto는 다음과 같습니다.

public record ProductDto(
        Long id,
        String name,
        int reviewScore,
        int reviewCount,
        int originalPrice,
        int salesPrice,
        List<String> productImages,
        List<String> productDetailImages
) {

    @QueryProjection
    public ProductDto { }

}

 

데이터를 조회 하고자 하는 의도가 담긴 Querydsl은 다음과 같습니다.

public ProductDto findSellingProductById(Long id) {
        return queryFactory
                .select(new QProductDto(
                        product.id,
                        product.name,
                        product.reviewScore,
                        product.reviewCount,
                        productOption.originalPrice,
                        productOption.salesPrice,
                        productImage.imageUrl,
                        productDetailImage.imageUrl
                ))
                .from(product)
                .leftJoin(product.productOptions, productOption)
                    .on(productOption.isDefault.isTrue(),
                        productOption.isSaleable.isTrue(),
                        productOption.isDeleted.isFalse())
                .leftJoin(product.productImages, productImage)
                    .on(productImage.isDeleted.isFalse())
                .leftJoin(product.productDetailImages, productDetailImage)
                    .on(productDetailImage.isDeleted.isFalse())
                .where(product.id.eq(id))
                .fetchOne();
}

 

Product, ProductOption, ProductImage, ProductDetailImage 엔티티는 다음과 같습니다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Product extends BaseDateTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "product_id")
    private Long id;

    @Column(length = 50)
    private String name;

    private int reviewScore;

    private int reviewCount;

    // ... 중략

    @OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
    private List<ProductImage> productImages = new ArrayList<>();

    @OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
    private List<ProductDetailImage> productDetailImages = new ArrayList<>();

    @OneToMany(mappedBy = "product", cascade = CascadeType.ALL)
    private List<ProductOption> productOptions = new ArrayList<>();

    // ... 중략
}

 

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ProductOption extends BaseDateTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "product_option_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id")
    private Product product;

    @Column(length = 30)
    private String name;

    private int originalPrice;

    private int salesPrice;

    // ... 중략

    private Boolean isDefault;

    private Boolean isSaleable;

    private Boolean isDeleted;

    // ... 중략
}

 

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ProductImage extends BaseDateTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "product_image_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id")
    private Product product;

    private String imageUrl;

    private Boolean isDeleted;

    // ... 중략
}

 

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ProductDetailImage extends BaseDateTimeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "product_detail_image_id")
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id")
    private Product product;

    private String imageUrl;

    private Boolean isDeleted;

    // .. 중략
}

 

감사합니다.

답변 1

답변을 작성해보세요.

1

안녕하세요. Anonymous님

이 부분은 스프링 부트와 JPA 활용2편 섹션 4에 있는 부분들을 참고해주세요 🙂

감사합니다.

Anonymous님의 프로필

Anonymous

질문자

2024.03.03

이해도 잘 되었고, 도움이 많이 되었습니다.

감사합니다^^