인프런 커뮤니티 질문&답변

psam1017님의 프로필 이미지
psam1017

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

상속관계 매핑

super class 를 필드로 가지는 엔티티에서 super 가 아닌, sub 로 가지고 올 때의 전략

해결된 질문

작성

·

402

·

수정됨

2

강의의 예제와 비슷하게, Item 과 Order 라는 엔티티가 있고 OrderItem 이라는 엔티티가 그 사이에서 "주문한 상품" 목록을 정의하고 있습니다. 이때 Order 는 일대다로 Set<OrderItem> 을 참조합니다.

그런데 회사에서 요구사항으로 Order 와 함께 각각 Item 의 서브타입인 Album, Movie, Book 정보를 모두 각각 조회해달라고 하는 상황입니다.

 

OrderItem 은 Item 만을 가지고 있기 때문에 구체 클래스인 Album 등을 orderItem.getAlbum(); 처럼 가져오지 못 하는 상황인데, 이때 이를 가져올 수 있는 전략에는 어떤 것들이 있을까요?

 

  1. itemId 로 다시 repository 로 데이터를 가져온다.

     

    Item getItem = orderItem.getItem();
    if (getItem.getType() == ALBUM) {
        Optional<Album> optAlbum = albumRepository.findById(getItem.getId());
    } else if ...

     

  2. OrderItem 이 super 클래스가 아니라 sub 클래스를 참조하도록 한다.

public class OrderItem {
    
    // ...
    @OneToMany(...)
    @JoinColumn(...)
    private Album album;


    @OneToMany(...)
    @JoinColumn(...)
    private Movie movie;

    // ...
}

 

일단 생각나는 방법은 위 2개인데, 각각 단점이 있다고 생각해서 개인적으로는 만족하지 못 한 상황입니다.

일단 위 방법 중 1번 방법으로 데이터를 반환해주고 있는 상황입니다. 2번은 테스트도 안 해보긴 했지만, 저렇게 하면 안 될 것 같아서요. 맘 같아선 API 분리해서 던져주고 싶은데 그러지도 못 하는 상황이고 ...

 

그냥 마법 같이 내가 가져온 Item 이 Album 타입이면 알아서 Album 으로 조회한다든지, 그런 기능이 있었으면 참 좋겠다 싶은 생각이 드네요

 

아무튼, 이렇게 super class 를 필드로 가지는 엔티티가 그 super class 를, 타입에 따라 알맞는 상속 받는 sub 클래스를 가져오려면 어떤 전략이나 기능을 사용해야 하고, 어떤 것들이 고려되어야 할까요?

 

늘 좋은 강의 감사합니다.

답변 2

3

psam1017님의 프로필 이미지
psam1017
질문자

김영한 선생님 말씀대로 형변환하니 코드가 깔끔해지고 로직도 단순해졌습니다. 제대로 확인해보니 getItemList() 를 호출하는 시점에 이미 (조인 전략에서) 일대다 테이블과 조인하면서 값을 다 들고 오네요

테스트와 로그 확인만 했어도 충분히 알 수 있었을 내용인데 제대로 확인하지 않았다니 부끄럽군요 오늘도 반성하고 갑니다...

======

그리고 제가 위에서 언급한 방법으로 가지고 오면 다음과 같은 WARNING 이 발생하니 오히려 하지 않는 게 더 권장됩니다.

 

HHH000179: Narrowing proxy to class - this operation breaks ==

 

WARNING 발생 원인과 시나리오 등이 궁금하신 분들은 아래 레퍼런스 읽어보세요~

https://web.archive.org/web/20221106215953/http://blog.marcinchwedczuk.pl/HHH000179-narrowing-proxy-to-class-this-operation-breaks-equality

 

======

02.13. update

형변환을 할 때, ClassCastException 이 발생할 수 있는데, 이는 현재 사용 중인 객체가 Entity 가 아니라 Proxy 이기 때문일 확률이 높습니다.

그럴 때는 Hibernate.unproxy(Object proxy) 를 사용하면 됩니다.

참고할 레퍼런스 남기겠습니다~

https://www.baeldung.com/hibernate-proxy-to-real-entity-object

 

2

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. psam1017님

가장 단순한 방법은 instance of를 활용해서 item 인스턴스의 타입을 확인한 다음에 Album, Movie, Book으로 다운 캐스팅해서 사용하시면 됩니다 🙂

감사합니다.

psam1017님의 프로필 이미지
psam1017
질문자

안 될 것 같아서 시도도 안 해봤는데 그게 되나 보네요...

역시 뭐든 직접 테스트를 해봐야 하나 봅니다.

다운캐스팅하고 Album 만의 필드의 데이터를 가지고 오는 시점이 궁금해지네요. 엔티티로 캐스팅하면 프록시도 적용이 되는지도 궁금하고... 직접 테스트해보면서 확인해야겠습니다

감사합니다

psam1017님의 프로필 이미지
psam1017

작성한 질문수

질문하기