ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JPA-Error] fetch join과 new 연산자를 통한 DTO 변환
    legacy/JPA 2024. 2. 6. 15:03

    문제 발생

    먼저 정의된 Entity를 먼저 보겠다.

     

    Member Entity

    Team과 N:1 연관관계에 있다.

       
    @Entity
    @Getter
    @Builder
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @AllArgsConstructor
    @ToString(of = {"id", "username", "age"})
    @NamedQuery(
            name = "Member.findByAgeGreaterThanAndUsername",
            query = "select m from Member m where m.age > :age and m.username = :username"
    )
    public class Member {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "member_id")
        private Long id;
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "team_id")
        private Team team;
    
        private String username;
        private int age;
    
        /**
         * 연관관계 편의 메서드
         */
        public void changeTeam(Team team) {
            this.team = team;
            team.getMembers().add(this);
        }
    }
       
    
    @Entity
    @Getter
    @Builder
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @AllArgsConstructor
    @ToString(of = {"id", "username", "age"})
    @NamedQuery(
            name = "Member.findByAgeGreaterThanAndUsername",
            query = "select m from Member m where m.age > :age and m.username = :username"
    )
    public class Member {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "member_id")
        private Long id;
    
        @ManyToOne(fetch = FetchType.LAZY)
        @JoinColumn(name = "team_id")
        private Team team;
    
        private String username;
        private int age;
    
        /**
         * 연관관계 편의 메서드
         */
        public void changeTeam(Team team) {
            this.team = team;
            team.getMembers().add(this);
        }
    }

     

    Team Entity

    Member 양방향 연관관계 필드를 선언하였다.

    @Entity
    @Getter
    @Builder
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @AllArgsConstructor
    @ToString(of = {"id", "name"})
    public class Team {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        @Column(name = "team_id")
        private Long id;
    
        @OneToMany(mappedBy = "team", fetch = FetchType.LAZY)
        @Builder.Default
        private List<Member> members = new ArrayList<>();
    
        private String name;
    }

     

    MemberRepository

    Member를 조회할 때 Team과 join, fetch join을 사용하여 조회하고 있다.

    public interface MemberSpringJpaRepository extends JpaRepository<Member, Long> {
    
        /**
         * join -> new 프로젝션 정상 수행
         */
        @Query(value = "select new study.datajpa.dto.MemberDto(m.id, m.username, t.name)
        		from Member m join m.team t")
        List<MemberDto> findMemberDtoWithJoin();
    
        /**
         * fetch join -> new 프로젝션 예외 터짐
         */
        @Query(value = "select new study.datajpa.dto.MemberDto(m.id, m.username, t.name)
        		from Member m join fetch m.team t")
        List<MemberDto> findMemberDtoWithFetchJoin();
    }

     

    Repository를 보면 join과 fetch join으로 조회하는 메서드가 존재한다. join과 달리 fetch join으로 조회하는 메서드를 호출하면 예외가 발생한다.

    문제 원인

    fetch join을 사용하고 new 연산자를 사용하여 dto로 변환할 수 없다. fetch join을 사용하는 이유는 Entity 상태에서 Entity Graph를 참조하기 위해서 사용하는 것이다. DTO는 Entity가 아니기 때문에 조회하는 것이 불가능하다. 

    문제 해결

    Entity로 반환하고 DTO로 변환하는 과정을 거친다.

    // Entity -> DTO 변환
    memberRepository.findMemberDtoWithJoin().stream()
            .map(member -> new MemberDto
                (member.getId(), member.getUsername(), member.getTeamName()));
Designed by Tistory.