스프링데이터 + JPA/QueryDSL

14. join

sdafdq 2023. 11. 29. 11:33
QMember m = QMember.member;
QTeam team = QTeam.team;

join(m.team, team)
join(조인할대상, 별칭으로사용할Q타입)

 

@Test
public void join(){
    List<Member> result = query.selectFrom(m).join(m.team, t).where(t.name.eq("teamA")).fetch();

    assertThat(result).extracting("username").containsExactly("member1", "member2");
}

m이 가지고 있는 team을 join해서 가지고 오고, 위에 QTeam = QTeam.team이라고 해놨다. 그 Q클래스를 별칭용 클래스로 쓸 것이다. 

extracting은 적출 이란 뜻인데, 해당 문자열인 이름의 필드를 찾아 Collection 형식으로 만드는 모양이다. 

거기에 containsExactly

https://qwefdg3.tistory.com/870

결과는 문제없이 통과했다.

 

/* select
    member1 
from
    Member member1   
inner join
    member1.team as team 
where
    team.name = ?1 */ select
        m1_0.member_id,
        m1_0.age,
        m1_0.team_id,
        m1_0.username 
    from
        member m1_0 
    join
        team t1_0 
            on t1_0.team_id=m1_0.team_id 
    where
        t1_0.name=?

이렇게 inner join으로 나간다. join(on에들어갈조건식)이기도 한 것 같다.

 

join()은 DB에서 처럼 inner join이고, left join, right join도 있다.

 

List<Member> result = query.selectFrom(m).leftJoin(m.team, t).where(t.name.eq("teamA")).fetch();
/* select
    member1 
from
    Member member1   
left join
    member1.team as team 
where
    team.name = ?1 */ select
        m1_0.member_id,
        m1_0.age,
        m1_0.team_id,
        m1_0.username 
    from
        member m1_0 
    left join
        team t1_0 
            on t1_0.team_id=m1_0.team_id 
    where
        t1_0.name=?

left join도 이렇게 의도했던 대로 잘 나간다.

 

on을 따로도 할 수 있는데, 그건 다음 장

 

 

세타 조인.

전혀 연관관계가 없는 것을 join 할 때.

@Test
public void theta_join(){
    em.persist(new Member("teamA"));
    em.persist(new Member("teamB"));
    em.persist(new Member("teamC"));

    List<Member> result = query.select(m).from(m, t).where(m.username.eq(t.name)).fetch();

    assertThat(result).extracting("username").containsExactly("teamA", "teamB");
}

그냥 임의로 Member이름을 teamA, B 등으로 등록했다.

 

쿼리 메소드를 보면

from에서 m, t

where에서 조건 후 가져온다.

 

from m,t는 m과 t를 곱하기, 즉 데이터 뻥튀기가 일어난다.

 

실제로

List<Tuple> result = query.select(m, t).from(m, t).fetch();

이렇게 해 보면 member 4개, team 2개 해서 사이즈가 8개가 나온다. member하나당 team이 2개씩 붙어서. 그러니까 모든 경우의 수와 비슷하다.

 

그러니까, 일단 from에서 m, t 가져와서 쫙 모든 경우의 수 리스트를 나열한 다음에, where의 조건으로 거기서 뽑는 것이다.

 

물론 DB 내부에서 알아서 최적화는 한다.

 

/* select
    member1 
from
    Member member1,
    Team team 
where
    member1.username = team.name */ select
        m1_0.member_id,
        m1_0.age,
        m1_0.team_id,
        m1_0.username 
    from
        member m1_0,
        team t1_0 
    where
        m1_0.username=t1_0.name

나가는 쿼리.

 

 

 

 

List<Tuple> result = query.select(m, t).from(m, t).fetch();

이거의 경우

/* select
    member1,
    team 
from
    Member member1,
    Team team */ select
        m1_0.member_id,
        m1_0.age,
        m1_0.team_id,
        m1_0.username,
        t1_0.team_id,
        t1_0.name 
    from
        member m1_0,
        team t1_0

그런데, 이렇게 세타 조인의 경우 아쉬운 점이, 보이는 바와 같이

left join이나 right join 등, outer join, 즉 외부조인이 안된다.

 

과거에는 안됐는데, 이제 연관관계가 없는 테이블을 on절을 이용해서 left join이 가능하다.

 

 

'스프링데이터 + JPA > QueryDSL' 카테고리의 다른 글

16. join fetch  (0) 2023.11.29
15. join on  (0) 2023.11.29
13. 그룹  (0) 2023.11.29
12. 페이징  (0) 2023.11.28
11. 정렬  (0) 2023.11.28