• 카테고리

    질문 & 답변
  • 세부 분야

    백엔드

  • 해결 여부

    미해결

EntityGraph을 할 때, 페치조인 대상이 여러 개인 경우

23.09.01 01:30 작성 조회수 196

0

안녕하세요. 강의를 듣고 개인 프로젝트 진행 중에 있는데, 궁금한게 있어서 질문드립니다.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class SecurityMedia {

    @Id
    @GeneratedValue
    @Column(name = "secu_no")
    private Long secuNo;       // 보안매체 번호(pk)
    

   ....


    @OneToMany(mappedBy = "kftcSecurityMedia", fetch = LAZY)
    private List<KftcToken> kftcToken = new ArrayList<>();    // 토큰

    @OneToMany(mappedBy = "kftcSecurityMedia") // 보안매체 이력
    private List<KftcSecurityMediaHistory> kftcSecurityMediaHistoryList = new ArrayList<>();

현재 SecurityMedia 라는 엔티티 객체에서 pk인 secuNo를 key로 하여

manyToOne 관계로 있는 TOKEN 클래스, HISTORY클래스를 가지고 오려고 합니다.

패치 조인을 하나 이상하면 조인 되는 ROW 수 때문에 총 데이터 갯수가 꼬여버릴 수 있다고 기억

하여.. SecurityMedia - Token / SecurityMedia - History 각각 패치조인 하여 가지고 오는 메소드

를 따려고 생각했습니다. 그런데 서비스 영역에서 이를 로직으로 표현하고자 할 때 어떤 식으로

표현을 해야할지 감이 잘 안 오는데요. token 리스트를 가지고 있는 SecurityMedia 객체 하나, History 리스트를 가지고 있는 SecurityMedia 객체 하나, 총 두 개의 객체가 만들어질텐데..

List<Token> tokenList = repository.findSecurityMediaWithToken(secuNo).getToken();

List<History> historyList = repository.findSecurityMediaWithHistory(secuNo).getHistory();

  1. 이렇게 각각 패치 조인으로 가지고온 데이터를 get하는 방식이 옳은 방식인지 의문입니다.

2. 각 리스트로 가지고 온 값에서 유효한 토큰, 최신 보안 이력 1개만 뽑아낼 생각인데 이것은 쿼리를 통해 전체 리스트를 받아오고, 서비스 영역에서 entity 함수로 원하는 값을 필터하는 식으로 대상을 추려내면 될까요? 아니면 레포지토리 영역에서 select한 리스트를 필터를 해줘서 서비스 영역에 리턴 해주는게 맞는걸까요?

 

 

답변 1

답변을 작성해보세요.

0

인프런 AI 인턴님의 프로필

인프런 AI 인턴

2023.09.03

안녕하세요, 인프런 AI 인턴이에요. EntityGraph를 사용하여 페치조인을 할 때, 페치조인 대상이 여러 개인 경우에는 어떻게 로직을 표현해야 하는지 궁금하신 것 같아요.

보통 EntityGraph를 사용할 때에는 JPQL이나 쿼리 메소드에 @EntityGraph 어노테이션을 사용하여 지정해줄 수 있습니다. 페치 조인 대상이 여러 개인 경우에는 @NamedEntityGraph를 사용해서 페치조인을 정의하는 것이 효과적입니다.

먼저, SecurityMedia 엔티티에 다음과 같이 NamedEntityGraph를 정의해볼 수 있어요.

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@NamedEntityGraph(name = "SecurityMedia.withTokenAndHistory", attributeNodes = {
    @NamedAttributeNode("kftcToken"),
    @NamedAttributeNode("kftcSecurityMediaHistoryList")
})
public class SecurityMedia {
    //...
}

그리고 이 NamedEntityGraph를 사용하여 JPQL이나 쿼리 메소드에 적용할 수 있습니다. 예를 들어, SecurityMedia 엔티티를 조회할 때 페치조인을 적용하려면 다음과 같이 할 수 있어요.

@EntityGraph(value = "SecurityMedia.withTokenAndHistory", type = EntityGraphType.FETCH)
@Query("SELECT sm FROM SecurityMedia sm WHERE sm.secuNo = :secuNo")
SecurityMedia findBySecuNoWithTokenAndHistory(@Param("secuNo") Long secuNo);

이렇게 하면 SecurityMedia 엔티티를 조회할 때, kftcToken과 kftcSecurityMediaHistoryList도 함께 로딩되어 페치조인이 되어 반환될 거예요.

페치 조인을 하나 이상할 경우에는 NamedEntityGraph를 사용하여 정의하고, JPQL이나 쿼리 메소드에 @EntityGraph 어노테이션을 사용하여 지정해주면 됩니다. 이렇게 하면 원하는 페치조인 대상을 가져올 수 있어요.

더 자세한 내용은 JPA 관련 문서 또는 강의를 참고해보시는 것을 추천드려요. 이해에 도움이 되셨으면 좋겠어요. 추가로 궁금한 점이 있으면 언제든지 물어보세요!

안녕하세요. 조언주신대로 해보니 다음과 같은 에러가 납니다 ㅠ

찾아보니.. 2개 이상에 OneToMany 자식 테이블에 패치조인을 선언했을 때 나는 에러라고 하는데.. 딱 제가 조인 하려는 케이스 같은데요. 이럴 때 대안으로 하나만 패치조인을 하고 나머지는 lazy 조인을 하라는게.. 인터넷 서치를 해본 결과 솔루션인데... 이거 말고 다른 방법으로 해결 할 수 있는 방법은 없을까요? 올바른 솔루션이 무엇일지 궁금합니다.

 

org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [com.project.kftcCenter.domain.securityMedia.model.KftcSecurityMedia.kftcSecurityMediaHistoryList, com.project.kftcCenter.domain.securityMedia.model.KftcSecurityMedia.kftcToken]