관리 메뉴

bright jazz music

[bootBoard] N:1(다대일) 연관관계: 7-1. JPQL과 left(outer) join 연관관계 O 본문

Framework/Spring

[bootBoard] N:1(다대일) 연관관계: 7-1. JPQL과 left(outer) join 연관관계 O

bright jazz music 2022. 9. 28. 20:22
  • 하나의 엔티티 타입을 이용하여 목록 화면에서 게시글의 정보와 함께 댓글의 수를 함께 가져올 수는 없다.
  • 이에 대한 해결책으로는 보편적으로 쓰이는 방법은 JPQL의 join을 이용하는 것이다.

1. left (outer) join

  • 스프링 부트 2버전 이후 포함되는 JPA(Java Persistence API) 버전은 엔티티 클래스 내에 전혀 연관관계가 없어도 join을 사용할 수 있다.
  • LEFT OUTER JOIN 혹은 LEFT JOIN 을 사용할 수 있다.
  • 조인 시 INNER JOIN 혹은 JOIN 과 같이 일반적인 조인 역시 사용할 수 있다.

 

엔티티 클래스 내부에 연관관계가 있는 경우

Board 엔티티 클래스의 경우 내부에 Member 엔티티 클래스를 변수로 가짐으로서 연관관계를 맺고 있다.

//Board.java
package com.example.bootboard.entity;

import lombok.*;

import javax.persistence.*;

@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@ToString(exclude = "writer")
public class Board extends BaseEntity{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long bno;

    private String title;

    private String content;

    @ManyToOne(fetch = FetchType.LAZY) //명시적으로 Lazy Loading 지정
    private Member writer; //FK 연관관계 지정

    //Board클래스는 Member클래스의 email(PK)를 FK로 참조하는 구조이다.

}

  이러한 경우 Board의 writer 변수를 이용하여 조인을 처리한다. (연관관계를 맺고 있는 엔티티 클래스의 변수명)

BoardRepository.java 인터페이스에 해당 코드를 작성해 준다.

//BoardRepository.java

package com.example.bootboard.repository;


import com.example.bootboard.entity.Board;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

public interface BoardRepository extends JpaRepository<Board, Long> {
    // 한 개의 로우(Object) 내에 Object[] 로 나옴
    
    @Query("select b, w from Board b left join b.writer w where b.bno =: bno")
    Object getBoardWithWriter(@Param("bno") Long bno); 
    
    //Board를 사용하지만 Member를 같이 조회해야 하는 상황
    //Board 클래스에는 Member와의 연관관계가 있으므로 b.writer와 같은 형태로 사용한다.
    // 이처럼 내부에 있는 엔티티를 이용할 때는 'LEFT JOIN' 뒤에 'ON'을 이용하는 부분이 없다.

}

작성을 완료했으니 테스트 코드로 getBoardWithWriter()를 확인한다.

 

//BoardRepositoryTests.java

...

@Test
public void testReadWithWriter() {
    Object result = boardRepository.getBoardWithWriter(100L);
    
    Object[] arr = (Object[]) result; //캐스팅

    System.out.println("----------------------------");
    System.out.println(Arrays.toString(arr));
}

 

에러 발생;

org.hibernate.QueryException: Named parameter not bound : bno; nested exception is java.lang.IllegalArgumentException: org.hibernate.QueryException: Named parameter not bound : bno

@Query("select b, w from Board b left join b.writer w where b.bno =: bno")
//마지막에 =: bno 사이를 띄어 써서 발생한 문제였음

아래와 같이 =:bno 붙여 쓰면 에러 소멸

 @Query("select b, w from Board b left join b.writer w where b.bno =:bno")

테스트 결과

=> 지연 로딩으로 설정되어 있음에도 쿼리는 조인 처리가 되어 한 번에 board 테이블과 member 테이블을 이용함.

Comments