기본 조인
-조인의 기본 문법
join(조인 대상, 별칭으로 사용할 Q타입)
teamA에 속하는 회원 조회(여기서는 member1,member2이다)
//팀A에 소속된 모든 회원
@Test
public void join() throws Exception{
QMember member= QMember.member;
QTeam team= QTeam.team;
List<Member> result= queryFactory
.selectFrom(member)
.join(member.team,team)//조인대상, 별칭으로 사용할 QType
.where(team.name.eq("teamA"))
.fetch();
assertThat(result)
.extracting("username")
.containsExactly("member1","member2")
}
기본 조인 쿼리
/* select
member1
from
Member member1
left join
member1.team as team
where //select 서브쿼리가 있다
team.name = ?1 */ select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
left outer join
team team1_
on member0_.team_id=team1_.team_id
where
team1_.name=?
세타 조인
연관관계가 없는 필드로 조인하는 것 -> from 절에 여러 엔티티를 선택한다 (from member, team)
이 조인은 외부 조인(outer join)이 불가능하다
내부 조인(inner join)만 가능
예제: 회원이름이 팀 이름과 같은 회원을 조회하려고 한다
@Test
public void theta_join() throws Exception {
em.persist(new Member("teamA"));
em.persist(new Member("teamB"));
List<Member> result = queryFactory
.select(member)
.from(member, team)
.where(member.username.eq(team.name))
.fetch();
assertThat(result)
.extracting("username")
.containsExactly("teamA", "teamB");
}
세타 조인 쿼리
/* select
member1
from
Member member1,
Team team
where
member1.username = team.name */ select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_ cross
join
team team1_
where
member0_.username=team1_.name
조인- On절
on절을 활용한 조인에는 1) 조인 대상 필터링 2) 연관관계 없는 엔티티 외부 조인 이 있다
1. 조인 대상 필터링
예시) 회원과 팀을 조인하면서, 팀 이름이 teamA인 팀만 조인하고, 회원은 모두 조회한다 -> leftJoin 이용
JPQL: SELECT m,t FROM Member m LEFT JOIN m.team t on t.name = 'teamA'
SQL: SELECT m.*, t.* FROM Member m LEFT JOIN Team t on m.TEAM_ID =t.id and t.name='teamA'
@Test
public void join_on_filtering() throws Exception {
//모든 멤버가 다 조회되고, 팀 이름이 teamA가 아니면 null 처리된다
List<Tuple> result = queryFactory
.select(member, team)
.from(member)
.leftJoin(member.team, team).on(team.name.eq("teamA"))
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
}
쿼리 결과
t=[Member(id=3, username=member1, age=10), Team(id=1, name=teamA)]
t=[Member(id=4, username=member2, age=20), Team(id=1, name=teamA)]
t=[Member(id=5, username=member3, age=30), null]
t=[Member(id=6, username=member4, age=40), null]
참고: Inner join에 on 절을 사용하면 where 절에서 필터링 하는 것과 기능이 동일하다.
따라서 inner join +on 절이면 익숙한 where 절로 해결하고, 외부조인이 필요한 경우에만 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) //일반 leftJoin에 엔티티 하나만 들어간다
.on(member.username.eq(team.name))
.fetch();
for (Tuple tuple : result) {
System.out.println("t=" + tuple);
}
}
연관관계에서의 leftJoin은 leftJoin(member.team, team) 이지만,
연관관계가 없는 곳에서 leftJoin은 leftJoin(team)으로 엔티티 하나만 들어간다
쿼리 결과
사용자 이름이 teamA,teamB인 경우만 팀 이름이 출력되었다
t=[Member(id=3, username=member1, age=10), null]
t=[Member(id=4, username=member2, age=20), null]
t=[Member(id=5, username=member3, age=30), null]
t=[Member(id=6, username=member4, age=40), null]
t=[Member(id=7, username=teamA, age=0), Team(id=1, name=teamA)]
t=[Member(id=8, username=teamB, age=0), Team(id=2, name=teamB)]
페치조인
@Test
public void fetchJoinUse() throws Exception {
em.flush();
em.clear();
Member findMember = queryFactory
.selectFrom(member)
.join(member.team, team).fetchJoin() //일반 join에 .fetchJoin() 추가해주면된다
.where(member.username.eq("member1"))
.fetchOne();
boolean loaded =
emf.getPersistenceUnitUtil().isLoaded(findMember.getTeam());
assertThat(loaded).as("페치 조인 적용").isTrue();
}
'QueryDSL' 카테고리의 다른 글
[Querydsl] 프로젝션(Projection) (0) | 2022.03.25 |
---|---|
[Querydsl] 서브쿼리 (from절 서브쿼리 한계) (0) | 2022.03.23 |
[Querydsl] 집합(groupBy, having) (0) | 2022.03.22 |
[Querydsl] 결과 조회, 정렬, 페이징 (0) | 2022.03.22 |
[Querydsl] 기본 검색 (0) | 2022.03.22 |