경로 표현식

2022. 4. 4. 16:42JPA 기초

용어 정리

• 상태 필드(state field): 단순히 값을 저장하기 위한 필드 (ex: m.username)
• 연관 필드(association field): 연관관계를 위한 필드
• 단일 값 연관 필드: @ManyToOne, @OneToOne, 대상이 엔티티(ex: m.team)
• 컬렉션 값 연관 필드: @OneToMany, @ManyToMany, 대상이 컬렉션(ex: m.orders)

경로표현식 특징

• 상태 필드(state field): 경로 탐색의 끝, 탐색이 더이상 불가능하다.
• 단일 값 연관 경로: 묵시적 내부 조인(inner join) 발생, 탐색이 가능하다.
• 컬렉션 값 연관 경로: 묵시적 내부 조인 발생, 탐색이 불가능하다.
컬렉션 값 연관경로는 FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능

경로 탐색 예시

1) 상태 필드(state field)

JPQL: select m.username, m.age from Member m

m.username은 상태필드이므로 더이상 탐색이 불가능하다. m.username이후 "."을 붙여도 탐색할 수 있는것이 없다.

2) 단일 값 연관 경로

JPQL: select o.member from Order o 
SQL:
select m.* 
 from Orders o 
 inner join Member m on o.member_id = m.id

Order와 Member는 다대일 관계이다. 다에서 1로 탐색하는 단일 값 연관경로다. 여기서는 탐색이 가능하다.
예를들면 
o.member.age , o.member.username으로 탐색이 가능하다. 여기서 또 다시, o.member.age는 아까 말한 상태필드이므로 더이상 탐색이 불가능하다.
근데 단일 값 연관경로의 주의사항은 묵시적 내부조인이 나간다는 점이다.
조인은 성능에 영향이 있으므로 조인 쿼리는 최대한 명시적으로 쓰는 것이 좋다.
지금은 join쿼리의 원인이 보일지라도 훨씬 복잡한 실무에서는 어디서 튀어나온 join쿼리인지 찾기 훨씬 힘들다.

예를 들어 다음과 같은 JPQL을 날리면

select m.team from Member m

이렇게 member와 team이 내부조인된 쿼리문이 발생한다. 나중에 쿼리가 수백개인데 이 Join이 어디에서 발생한 것인지 알 수 있을까 싶다. 그러니 조인을 해야 할 때는 명시적으로 join키워드를 쿼리문에 포함하자. 참고로 이런 묵시적 조인은 내부조인만 가능하다. outer, left 등 외부 조인을 하고싶다면 명시적 조인을 하자.

 

3) 컬렉션 값 연관경로

 select t.members from Team t

1:N 관계이며 Team이 1 Member가 N이다.
이때 team의 List<Member>를 select하는 쿼리문인데, 여기까지는 가능하다. 하지만

select t.members.username from Team t

members라는 컬렉션에서는 경로 탐색이 불가능하다. 컬렉션에는 객체가 여러개 저장되어 있을 터인데, 그 중 어떤 객체의 username인지 알 수 없기 때문이다.

다행히도 컬렉션 값 연관경로는 FROM 절에서 명시적 조인을 통해 별칭을 얻으면 별칭을 통해 탐색 가능하다.

select m.username from Team t join t.members m      가능하다!!