@Test
public void join() throws Exception{
List<Member> result = queryFactory
.selectFrom(member)
.join(member.team, team)
.where(team.name.eq("teamA"))
.fetch();
for (Member m : result) {
assertThat(m.getTeam().getName()).isEqualTo("teamA");
}
}
/**
* 세타 조인
* 회원의 이름이 팀 이름과 같은 회원 조회
*/
@Test
public void theta_join() throws Exception{
// 세타조인 예제를 위한 엔티티
em.persist(new Member("teamA"));
em.persist(new Member("teamB"));
// 세타조인 = 조인 + where
List<Member> result = queryFactory
.select(member)
.from(member, team) //모든 member와 team을 모두 조인 (연관관계가 없더라도 전부 다 조인)
.where(member.username.eq(team.name)) // 조인된 엔티티들중 member.username == team.name인 엔티티만 조회
.fetch();
assertThat(result.get(0).getUsername()).isEqualTo("teamA");
assertThat(result.get(1).getUsername()).isEqualTo("teamB");
}
세타 조인 예제에서 보이듯이 from()에 member와 team을 넣으면 연관관계가 없는 경우에도 관계없이 모든 member와 team이 조인된다(막 조인). 따라서 테이블이 뻥튀기 될 수 있다. 만일 member가 4개 team이 3개인 경우 from(member, team)을 하게 되면 총 12개의 member가 조회될 것이다.
from()으로 인한 데이터 뻥튀기 예제
- 이미 member1,2,3,4와 teamA,B,C가 저장되어 있다.
@Test
@Rollback(value = false)
public void theta_join2() throws Exception{
// from()으로 인한 데이터 뻥튀기
List<Member> result = queryFactory
.select(member)
.from(member, team) //모든 member와 team을 모두 조인 (연관관계가 없더라도 전부 다 조인)
.fetch();
for (Member m : result) {
System.out.println("m = " + m + " m.team= "+m.getTeam());
}
}
출력>>>
m = Member(id=3, username=member1, age=10) m.team= Team(id=1, name=teamA)
m = Member(id=3, username=member1, age=10) m.team= Team(id=1, name=teamA)
m = Member(id=3, username=member1, age=10) m.team= Team(id=1, name=teamA)
m = Member(id=4, username=member2, age=20) m.team= Team(id=1, name=teamA)
m = Member(id=4, username=member2, age=20) m.team= Team(id=1, name=teamA)
m = Member(id=4, username=member2, age=20) m.team= Team(id=1, name=teamA)
m = Member(id=5, username=member3, age=30) m.team= Team(id=2, name=teamB)
m = Member(id=5, username=member3, age=30) m.team= Team(id=2, name=teamB)
m = Member(id=5, username=member3, age=30) m.team= Team(id=2, name=teamB)
m = Member(id=6, username=member4, age=40) m.team= Team(id=2, name=teamB)
m = Member(id=6, username=member4, age=40) m.team= Team(id=2, name=teamB)
m = Member(id=6, username=member4, age=40) m.team= Team(id=2, name=teamB)
4(member) x 3(team) = 12번 조회된다. 쿼리가 12번 나간다는 말은 아니고 조인된 테이블의 행 수가 12개가 된다는 말이다.
On
하이버네이트 5.1부터 on 을 사용해서 서로 관계가 없는 필드로 외부 조인하는 기능이 추가되었다. 물론 내부 조인도 가능하다.
주의! 문법을 잘 봐야 한다. leftJoin() 부분에 일반 조인과 다르게 엔티티 하나만 들어간다.
- 일반조인: leftJoin(member.team, team) ( -> fk와 pk로 조인)
- on조인: from(member).leftJoin(team).on(xxx) ( -> 막 조인 후 on으로 필터링)
/**
*2. 연관관계 없는 엔티티 외부 조인
*예)회원의 이름과 팀의 이름이 같은 대상 외부 조인
* JPQL: SELECT m, t FROM Member m LEFT JOIN Team t on m.username = t.name
* SQL: SELECT m.*, t.* FROM Member m LEFT JOIN Team t ON m.username = t.name */
@Test
public void join_on_no_relation() throws Exception {
em.persist(new Member("teamA"));
em.persist(new Member("teamB"));
List<Tuple> result = queryFactory
.select(member, team)
.from(member)
.leftJoin(team).on(member.username.eq(team.name))
.fetch();
for (Tuple tuple : result) {
System.out.println("t=" + tuple);
}
}
페치 조인
페치 조인을 하기위해서는 join(), leftJoin()과 같은 조인 메서드 뒤에 fetchJoin() 메서드를 붙여준다. 페치 조인을 하게 되면 연관된 엔티티를 모두 즉시로딩으로 한번에 조회해 온다.
Member findMember
= queryFactory
.selectFrom(member)
.join(member.team, team). fetchJoin() // 페치 조인 적용. member의 엔티티 다 끌고옴.
.where(member.username.eq("member1"))
.fetchOne();
'Spring > Querydsl' 카테고리의 다른 글
Querydsl- 동적쿼리 (0) | 2023.08.05 |
---|---|
Querydsl- 프로젝션 (0) | 2023.08.04 |
Querydsl- 집합 (0) | 2023.07.26 |
Querydsl- 정렬과 페이징 (0) | 2023.07.25 |
Querydsl- Q 인스턴스 (0) | 2023.07.22 |