ON절을 활용해 조인(JPA 2.1 부터 지원)
- 조인 대상 필터링
- 연관관계 없는 엔티티 외부 조인 => 이게 많이 쓰인다.
조인 on절 test를 돌려보면
/**
* 예) 회원과 팀을 조인하면서, 팀 이름이 teamA인 팀만 조인, 회원은 모두 조회
* // 회원이랑 팀을 조회하면서 조인을 하는데 팀의 이름이 teamA인 애만 가지고 온다.
* JPQL: select m, t from Member m left join m.team t on t.name = 'teamA'
*/
@Test
public void join_on_filtering() {
// Tuple가 나온 이유는 select절이 여러개이기 때문이다.
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);
}
}
실행결과 아래와 같다.
/* select
member1,
team
from
Member member1
left join
member1.team as team with team.name = ?1 */
// team의 이름까지 걸러내어 join이 된다.
select
member0_.id as id1_1_0_,
team1_.id as id1_2_1_,
member0_.age as age2_1_0_,
member0_.team_id as team_id4_1_0_,
member0_.username as username3_1_0_,
team1_.name as name2_2_1_
from
member member0_
left outer join
team team1_
on member0_.team_id=team1_.id
and (
team1_.name=?
)
// teamB는 날라갔지만 left join이기 때문에 null로 나오게 된다.
tuple = [Member(id=3, username=member1, age=10), Team(id=1, name=teamA)]
tuple = [Member(id=4, username=member2, age=20), Team(id=1, name=teamA)]
tuple = [Member(id=5, username=member3, age=30), null]
tuple = [Member(id=6, username=member4, age=40), null]
그냥 join으로 바꾸면 어떻게 될까
@Test
public void join_on_filtering() {
// Tuple가 나온 이유는 select절이 여러개이기 때문이다.
List<Tuple> result = queryFactory
.select(member, team)
.from(member)
.join(member.team, team).on(team.name.eq("teamA"))
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
}
teamB는 같이 join하는 대상이 없기 때문에 빠져버리게 된다.
tuple = [Member(id=3, username=member1, age=10), Team(id=1, name=teamA)]
tuple = [Member(id=4, username=member2, age=20), Team(id=1, name=teamA)]
on절을 where절로 바꿀수가 있다.
@Test
public void join_on_filtering() {
// Tuple가 나온 이유는 select절이 여러개이기 때문이다.
List<Tuple> result = queryFactory
.select(member, team)
.from(member)
.join(member.team, team)
// .on(team.name.eq("teamA"))
.where(team.name.eq("teamA"))
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
}
위와 똑같이 결과 1 2만 나오게 된다.
tuple = [Member(id=3, username=member1, age=10), Team(id=1, name=teamA)]
tuple = [Member(id=4, username=member2, age=20), Team(id=1, name=teamA)]
leftJoin으로 해야 할 상황이 오면 where절을 쓰면 된다.
- on절을 활용해 조인 대상을 필터링 할 때, 외부조인이 아니라 내부조인 inner join을 사용하면 where 절에서 필터링 하는 것과 동일
- on 절을 활용한 조인 대상 필터링을 사용할 때, 내부조인이면 where 절로 해결 / 외부조인이 필요한 경우에만 이러한 기능 사용
@Test
public void join_on_filtering() {
// Tuple가 나온 이유는 select절이 여러개이기 때문이다.
List<Tuple> result = queryFactory
.select(member, team)
.from(member)
.join(member.team, team)
// inner join이면 on 절로 걸러내나 where에 넣나 결과가 똑같다.
// .on(team.name.eq("teamA"))
// 만약 leftJoin(member.team, team)으로 해야 할 상황이 오면
// where로 해서 풀면된다.
.where(team.name.eq("teamA"))
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
}
정리를 하자면
@Test
public void join_on_filtering() {
// Tuple가 나온 이유는 select절이 여러개이기 때문이다.
List<Tuple> result = queryFactory
.select(member, team)
.from(member)
.leftJoin(member.team, team)
// on절로 join 하려는 대상을 줄여서 join을 할 수 있다.
// 보통 left join인 경우에만 의미가 있다.
// inner join이면 where절에서 결과가 걸러진다.
// 즉 join 대상을 필터링 해서 가져와야 하는데 left join을 쓰는 경우에는 on 절을 활용하자.
// team 의 데이터를 줄여서 그걸 가져온다. 만약 팀의 대상을 줄였는데 leftJoin이 아니고 innerjoin이다
// 그러면 그냥 where 절에서 정리를 하는게 더 깔끔하다.
.on(team.name.eq("teamA"))
// .where(team.name.eq("teamA"))
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
}
연관관계가 없는 엔티티를 외부 조인 해보자.
@Test
public void join_on_no_relation() {
em.persist(new Member("teamA"));
em.persist(new Member("teamB"));
em.persist(new Member("teamC"));
List<Tuple> result = queryFactory
.select(member, team)
// from 해서 member를 join을 하는데
// 보통은 member.team 이렇게 한다.
// 여기서는 leftJoin(team) 썼다. => id를 매칭 안해서 (member.username.eq(team.name)) 이름으로만 join을 한다.
.from(member)
//.leftJoin(member.team, team)
// member team 막 조인을 한다 이런 경우에는 on을 이용
// on절을 필터를 줄이는 역할
.leftJoin(team).on(member.username.eq(team.name))
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
}
member의 이름과 team의 이름이 같은 경우에는 오른쪽에 있는 조인 대상을 실행결과만큼만 가져오게 된다.
on(member.username.eq(team.name))
실행결과는 아래와 같다.
tuple = [Member(id=3, username=member1, age=10), null]
tuple = [Member(id=4, username=member2, age=20), null]
tuple = [Member(id=5, username=member3, age=30), null]
tuple = [Member(id=6, username=member4, age=40), null]
tuple = [Member(id=7, username=teamA, age=0), Team(id=1, name=teamA)]
tuple = [Member(id=8, username=teamB, age=0), Team(id=2, name=teamB)]
// 오른쪽 대상을 필터링해서 없기 때문에
// on(member.username.eq(team.name)) 조건을 만족하지 않는다.
tuple = [Member(id=9, username=teamC, age=0), null]
그냥 join을 하게 되면 null이 다 없어지게 된다.
@Test
public void join_on_no_relation() {
em.persist(new Member("teamA"));
em.persist(new Member("teamB"));
em.persist(new Member("teamC"));
List<Tuple> result = queryFactory
.select(member, team)
// from 해서 member를 join을 하는데
// 보통은 member.team 이렇게 한다.
// 여기서는 leftJoin(team) 썼다. => id를 매칭 안해서 (member.username.eq(team.name)) 이름으로만 join을 한다.
.from(member)
// member team 막 조인을 한다 이런 경우에는 on을 이용
// on절을 필터를 줄이는 역할
.join(team).on(member.username.eq(team.name))
.fetch();
for (Tuple tuple : result) {
System.out.println("tuple = " + tuple);
}
}
/* select
member1,
team
from
Member member1
inner join
Team team with member1.username = team.name */
// on절에서 usernam이랑 team이름이 같다 이거만 있다.
select
member0_.id as id1_1_0_,
team1_.id as id1_2_1_,
member0_.age as age2_1_0_,
member0_.team_id as team_id4_1_0_,
member0_.username as username3_1_0_,
team1_.name as name2_2_1_
from
member member0_
inner join
team team1_
on (
member0_.username=team1_.name
)
즉 member.team 이 있으면 id가 매칭된것이 들어가게 되고
.leftJoin(member.team, team).on(member.username.eq(team.name))
없으면 member0_.username=team1_.name 이거만 필터링 하게 된다.
.leftJoin(team).on(member.username.eq(team.name))
- 하이버네이트 5.1부터 `on`을 사용해서 서로 관계가 없는 필드로 외부 조인하는 기능이 추가 / 내부 조인도 가능
- leftJoin() 부분에 일반 조인과 다르게 엔티티 하나만 들어감.
- 일반조인 -> leftJoin(member.team, team)
- on조인 ->from(member).leftJoin(team).on(xxx)
<출처 김영한: 실전! Querydsl >
https://www.inflearn.com/course/Querydsl-%EC%8B%A4%EC%A0%84/dashboard
실전! Querydsl - 인프런 | 강의
Querydsl의 기초부터 실무 활용까지, 한번에 해결해보세요!, - 강의 소개 | 인프런...
www.inflearn.com
'Spring > QueryDSL' 카테고리의 다른 글
서브 쿼리 (0) | 2022.04.20 |
---|---|
조인 - 페치 조인 (0) | 2022.04.20 |
조인 - 기본 조인 (0) | 2022.04.20 |
집합 (0) | 2022.04.20 |
정렬 & 페이징 (0) | 2022.04.20 |