티스토리 뷰
문제 발생
먼저 정의된 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()));