인프런 커뮤니티 질문&답변

jaesungyoun님의 프로필 이미지
jaesungyoun

작성한 질문수

실전! Querydsl

querydsl fetchjoin + Projections.bean을 활용한 특정필드 dto 매핑(feat. query specified join fetching, but the owner of the fetched association was not present )

작성

·

121

·

수정됨

0

queryFactory.select(Projections.bean(GetMyCommentResponse.MyCommentInfo.class,
                commentEntity.id.as("commentId"),
                commentEntity.content.as("content"),
                commentEntity.likeCount.as("likeCount"),
                commentEntity.createDateTime.as("createDateTime"),
                Projections.bean(
                        GetMyCommentResponse.MyCommentedPopUpInfo.class,
                        postEntity.id.as("postId"),
                        postEntity.name.as("postName"),
                        postEntity.mainImageUrl.as("mainImageUrl"),
                ).as("postInfo"),
                  // commentEntity // 엔티티도 같이 조회하면 에러가 나지 않음
        ))
        .from(commentEntity)
        .join(commentEntity.post, postEntity).fetchJoin()

 

안녕하세요 영한님!

강의 잘 듣고 있습니다.

공부 중에 코드를 작성하다

query specified join fetching, but the owner of the fetched association was not present in the select list
이런 에러가 발생했는데, fetchjoin시 실제 질의하는 대상 Entity를 select절에 쓰지않아서 에러가 나더라구요. select절에 commentEntity를 추가하면 에러가 발생하지 않지만 이미 commentEntity의 필드들은 모두 가져왔는데, 또 조회하는게 불필요한 작업이라고 생각되어서요. 그렇다고, fetchjoin이 아닌 일반 조인을 써버리면 코멘트마다 포스트에 대해서 n+1 문제가 발생할 것이라고 생각되구요

이러한 상황에서 좋은 해결방법이 있을까요?

 

감사합니다

답변 2

0

안녕하세요. jaesungyoun님, 공식 서포터즈 y2gcoder입니다.

간단하게 말씀드리자면, fetch join을 사용할 때는 엔티티 를 대상으로 해야 하기 때문입니다!
fetchJoin()을 지워보시겠습니까?

 

감사합니다.

jaesungyoun님의 프로필 이미지
jaesungyoun
질문자

답변 감사합니다

넵 지우면 에러 없이 동작하는데 그럼 n+1문제를 해결할 수 없지 않나요?

음 이경우에는 애시당초 jpql을 만들 때 미리 조인해서 조회하도록 하고 있기 때문에 fetch join과 상관이 없을 것 같습니다! 저는 fetch join은 조인해서 같이 불러온 연관 엔티티를 미리 영속성 컨텍스트에 넣어놓기 위한 기능이라고 생각합니다
이는 현재 DTO 조인에서는 필요없는 기능이라고 생각합니다 🙂 이미 JPQL 상으로는 jaesungyoun님께서 조인 문을 통해 연관된 postentity를 조회하고 있으십니다!

jaesungyoun님의 프로필 이미지
jaesungyoun
질문자

제가 잘 이해가 안 돼서 한 번 더 여쭤볼 수 있을까요?
보통 JPQL에서 JOIN문을 써도 엔티티 대상을 조회하기 위한 쿼리 1 + 그 대상을 통해 연관된 엔티티를 불러오기 위한 쿼리 N 이렇게 해서 1+N(N+1) 문제가 발생하는 것인데, 이 경우도 똑같지않나요? JPQL에서 join을 썼다고해서 모든 연관된 엔티티를 불러오는 것이 아니라고 생각이 됩니다!!... 제가 오해하고 있는 부분이 있으면 편하게 말씀부탁드립니다..!

 

제가 설명을 명확하게 못한 것 같습니다 🙂

  1. 엔티티 조회와 DTO 조회의 차이
    엔티티 조회 시, 연관된 엔티티를 가져오는 방법 중 하나로 fetch join을 사용합니다. fetch join을 사용하면, 연관된 엔티티도 함께 조회하여 영속성 컨텍스트에 저장되므로 N+1 문제를 피할 수 있습니다. 이는 CommentEntity를 조회할 때 연관된 PostEntity도 함께 영속성 컨텍스트에 관리되도록 합니다.
    반면에 DTO를 조회하는 경우, JPQL에서 직접 필드나 프로퍼티를 지정하여 필요한 데이터만 가져옵니다. 이때는 엔티티 간의 연관 관계가 아닌, 단순히 필요한 데이터만을 가져오게 됩니다. 따라서 이 경우에는 fetch join이 필요하지 않으며, 단순히 조인하여 데이터를 가져오고 DTO에 매핑하는 것만으로 충분합니다.

  2. N+1 문제와 일반 조인
    fetch join이 없는 일반 조인의 경우, 엔티티가 프록시로 로드되며 연관된 엔티티에 접근할 때마다 추가적인 쿼리가 발생하여 N+1 문제가 발생할 수 있습니다. 하지만 DTO를 조회하는 경우에는, 처음부터 조인을 통해 필요한 데이터를 모두 가져오므로 추가적인 쿼리가 발생하지 않아 N+1 문제가 발생하지 않습니다.

요약하자면, 지금은 DTO를 조회하는 상황이기 때문에 엔티티 조회 시 발생할 수 있는 N+1 문제는 발생하지 않으며, fetch join을 사용할 필요도 없습니다. 일반 조인을 통해 필요한 데이터를 한 번에 가져오는 것이 더 적합합니다!

 

0

안녕하세요, 인프런 AI 인턴입니다.

jaesungyoun님의 Querydsl 관련 질문에 대해서는 다음 자료가 도움이 될 것 같습니다.

*Querydsl에서 Fetch Join 시에 특정 필드들만 DTO로 조회하고 싶을 때 발생하는 문제*와 관련하여, jaesungyoun님이 겪고 계신 문제는 “Fetch Join을 사용할 때, 조인된 엔티티의 일부 필드만 선택하여 DTO로 직접 조회하고자 할 때” 발생하는 보편적인 문제입니다. 이 경우, Querydsl은 조인된 엔티티 전체가 아닌 특정 필드만을 조회하고자 할 때 에러를 발생시킬 수 있습니다.

다만, jaesungyoun님의 경우에는 Fetch Join과 함께 Projections.bean을 사용하여 DTO로 필드를 매핑하는 과정에서 에러가 발생한 것으로 보입니다. 에러 메시지는 “query specified join fetching, but the owner of the fetched association was not present in the select list”의 핵심은 “Fetch Join을 사용하였지만, 선택된(select) 목록에 join 대상이 포함되지 않았다”는 것을 알려줍니다.

해당 문제를 해결하기 위한 방법으로는 다음 두 가지 접근이 있을 수 있습니다:
1. Fetch Join 대신 일반 Join 사용 후, Batch Size 설정: Fetch Join은 엔티티 전체를 로딩하는데 초점을 맞추기 때문에 원하는 필드만 선택하여 DTO로 직접 조회하는 경우에는 적합하지 않을 수 있습니다. 대신 일반 Join을 사용하고, @BatchSize 애너테이션 또는 spring.jpa.properties.hibernate.default_batch_fetch_size 설정을 통해 N+1 문제를 완화할 수 있습니다.
2. Querydsl의 fetch 결과를 직접 DTO로 변환: Fetch Join을 사용하지 않고, 결과를 List 형태로 받아온 후 자바 스트림 등을 사용하여 DTO로 수동 매핑하는 방법이 있습니다. 이 방법은 원하는 필드만 선택하여 DTO를 생성할 수 있는 장점이 있으나, 코드가 다소 복잡해질 수 있습니다.

현재 문의해주신 상황에서는 직접적으로 유사한 예제나 답변을 제공 드릴 구체적인 링크가 없습니다. 그러나 Querydsl 관련 문제나 Fetch Join의 사용법에 대해 더 자세히 알고 싶다면, Querydsl 공식 문서 또는 다음 자료를 참고하실 것을 권장드립니다:

  • 실전! Querydsl (영한님 강의) 에서 제공되는 심화 내용 및 최적화 팁
  • Querydsl의 Fetch Join 사용법: Fetch Join 사용 시 발생한 문제와 그 해결 방법에 대해 논의된 Q&A

저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.

jaesungyoun님의 프로필 이미지
jaesungyoun

작성한 질문수

질문하기