기본 조인

-조인의 기본 문법

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(); 
}

+ Recent posts