본문 바로가기
IT 공부/자바와 웹 애플리케이션

[JPA] - 지연 로딩이어도 연관관계의 엔티티가 Null은 아니다.

by exdus3156 2024. 1. 29.

 

1. 문제 의식

지연 로딩(링크)이 설정된 엔티티를 가져오는 경우,Transaction 범위 내에서 연관관계에 있는 엔티티를 구체적으로 요청하지 않는 이상 내부 엔티티 로딩은 지연된다.

예를 들어, 아래의 엔티티가 있다.

@Entity
public class Reply {

    @Id
    @GeneratedValue(GenerationType.INDENTITY)
    private Long rno;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "board_bno")
    priate Board board;
    
}

 

이 엔티티를 가져오는 아래의 코드에서는 Reply 엔티티 내부의 Board 객체는 지연 로딩으로 설정되었으므로 DB처리가 되지 않을 것이다.

public class TestCode {
    private ReplyRepository replyRepository;

    @Test
    public void test() {
        Optional<Reply> option = replyRepository.findById(100L);
        Reply reply = option.orElseThrow();
        
        // ...
    }
    
}

 

그렇다면 Reply 엔티티 객체 내부의 board 필드는 아예 null인걸까?

 

사실 이 부분을 테스트하기는 쉽지 않다. 왜나하면 reply 엔티티 내의 board 필드가 null인지 확인하기 위해 getBoard()를 수행하는 순간 즉시 DB 처리가 실행되기 때문이다. 알고 싶은 것은, findById() 메소드 이후에 얻은 reply 객체의 board가 null로 설정되는지 알고 싶은 것이다.

 

 

2. 결론

결론부터 말하자면, findById()를 통해 얻은 reply 엔티티 객체 내부의 board는 null이 아니다. 정확하게는 bno만 설정된 텅 빈 Board 엔티티 객체가 만들어진다. 즉, 아래의 테스트는 별도의 @Transactional 설정 없이도 테스트를 통과하는 것으로 실험 확인되었다.

public void TestCode {

    @Test
    public void test() {
        Optional<Reply> option = replyRepository.findById(100L);
        Reply reply = option.orElseThrow();
        Assertions.assertNotNull( reply.getBoard().getBno() );
    }
    
}

 

즉, getBoard()를 통해 board 객체 자체를 얻어야 하는 경우 DB 처리를 통해 지연 로딩되지만, reply 테이블에서 함께 가져온 board_bno 값은 저장되어 있기 때문에 이 bno 값만 원하는 경우엔 로딩이 되지 않는 것이다.

의문이 해결되었다.. 즉, 지연 로딩이라고 하더라도 정말로 내부의 엔티티를 아예 가져오질 않아 null로 설정되는 것이 아니다. FK인 Id 값만이 설정된 엔티티가 생성이 되는 것이다. 

만약 지연 로딩이라는 이유로 연관관계에 있는 엔티티를 아예 들고 오질 않아 null로 만들어버렸다면, Model Mapper와 같은 매핑 라이브러리로 엔티티를 DTO로 변환할 때 내부 엔티티의 id 값이 문제 없이 잘 설정되는 현상은 미스터리에 빠진다.

그러나 지연 로딩이여도 함께 가져온 FK를 설정하기 위한 내부 엔티티는 만들어주기 때문에 Model Mapper도 잘 작동하는 것이다!!