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

시큐웨어님의 프로필 이미지
시큐웨어

작성한 질문수

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

경로 표현식

이런식의 연관관계도 가능한가요?

작성

·

337

0

안녕하십니까. ^^

mybatis만 사용했다가 JPA강의를 보고  감명받아 신규프로젝트에 처음으로 jpa를 도입해보고자 하는데 엔티티 구현 중 막히는 부분이 있어 질문드립니다.

 

개발중인 시스템의 사용자 구분은 '소방'과 '의사'로 구분되고 추후 더 늘어날수 있는 상황입니다.

 

사용자(USERS)라는 테이블이 있고 여기엔 계정정보 및 공통적인 데이터들이 있습니다.

소방 사용자의 경우 소방과 관련된 추가 데이터, 의사 사용자의 경우 또 관련된 추가 데이터가 있어야 되는 상황입니다.

 

그래서 각각 USER_PROFILE_FIRE,  USER_PROFILE_DOCTOR 라고 테이블을 만들어서 그곳에 관련 데이터를 담고싶습니다.

사용자(USERS) 테이블에 각각의 프로필에 필요한 모든 컬럼을 넣기에는 양이 너무 많고 확장성도 좋지 않다고 생각해서 입니다.

 

USER_PROFILE_FIRE,  USER_PROFILE_DOCTOR 테이블들은 추가 데이터를 담기위한 용도일뿐 각각의 테이블이 별도 조회될 일은 없고 모두 USERS 테이블을 조회하면서 상황에 맞게 같이 불러와지면 됩니다.

이를테면 user.profile로 접근하면 소방일때는 소방프로필, 의사일때는 의사프로필을 접근할수 있으면 좋을것 같은데 이게 JPA로 가능한지 모르겠습니다.

 

public class User {
   @Id @GeneratedValue
   private Long id;

   private String userId;

   private String password;

   private String name;

   private UserType type;   //  의사 or 소방 

   @OneOnOne
   private ???   profile;   // 의사일때는 USER_PROFILE_DOCTOR,  소방일땐 USER_PROFILE_FIRE의 데이터

}

요약하면 위 코드 같은 구현이 가능한지 입니다.

 

 

안된다면 사용자 엔티티에 

private ProfileHosp profileHosp; // 의사 프로필
private ProfileFire profileFire;  // 소방 프로필 

이런식으로 놓고 모두 연관관계를 맺어야 하는건가요?
이러면 사용자 불러올때 두 테이블 모두 조인해서 좋지 않은것같은데..

상속관계매핑은 아닌것 같고 어떻게 해야될지 감이 안잡힙니다 ㅜㅜ

답변 2

0

시큐웨어님의 프로필 이미지
시큐웨어
질문자

영한님 먼저 답변 진심으로 감사드립니다.^^

질문이 정리가 안되고 횡설수설 한것같아 다시 정리해서 질문드립니다 ㅜㅜ

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item {

    @Id
    @GeneratedValue
    @Column(name = "item_id")
    private Long id;

    private String name;
    private int price;

}

 

@Entity
@DiscriminatorValue("B")
public class Book extends Item {
    private String author;
    private String isbn;
}

@Entity
@DiscriminatorValue("A")
public class Album extends Item {
    private String artist;
}

@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
    private String director;
    private String actor;
}

 

 

상속 연관관계에서 가장 많은 예시로 사용되는 Item 과  Movie, Album, Book 예시로 질문드립니다

위의 예시에서 각각 Book, Movie, Album의 Repository가 만들어지고 

 

@Repository
public interface ItemRepository<T extends Item> extends JpaRepository<T, String> {

}

 

ItemRepository는 위와 같이 구현 되었다고 볼때  

이런식으로 사용될수도 있지만 

List<Book> bookList = bookRepository.findAll();
List<Movie> movieList = movieRepository.findAll();
List<Album> bookList = albumRepository.findAll();

 

아래와 같이 Item으로 받을수도 있는데, 그때 아래와 같이 getClass하거나 instansof를 통해 어떤 자식클래스인지 확인 가능하고 형변환도 가능한것을 확인했습니다.

List<Item> itemList = itemRepository.findAll();

for(Item item : itemList){
    System.out.println(item.getClass().toString());  //  Book, Album,  Movie 클래스임을 확인.
}

 

질문: 

로직상 Book, Album, Movie를 직접 조회할일은 거의 없고
Item 만으로 조회해야되는 일이 빈번할 경우는 어떤식으로 로직을 짜야할지모르겠습니다.

시스템입장에선 조회 전에 내가 조회할게 Book인지 Movie인지 모르는 상황이라 Item으로 조회해야만 하는 상황이고

조회 후에 아래 코드 처럼 instanceof를 통해 형변환 해주면 된다 치지만 

// 단일 조회일 경우
Item item = itemRepository.findById(id);   
Book book;
if(item instanceof Book){
   book = (Book) item;   
}

 

단일 조회가 아닌 전체 리스트 조회일경우는 어떤식으로 해야하는지 감이 안잡힙니다 ㅜㅜ

// 리스트 조회할경우 ?
List<Item> itemList = itemRepository.findAll();   
for(Item item : itemList){
  ???
}

 

리스트로 조회할때 ORDER BY나 페이징 까지 고려되서 소트된 데이터가 올거라 

포문 돌면서 형변환 하고 각각의 리스트에 다시 담기도 어렵고 

 

JPA를 이용해 애초에 받아올때 각각 맞는 클래스에 맞게 받아와서 하나의 리스트에 담는 방법이 없나요?
bookList, movieList가 아닌 ItemList 하나만 존재해야 할경우 어떤식으로 해야하나요?

List<T extends Item>  itemList ;   <<-   이런식으로 item을 상속받는 객체를 담은 리스트를 만들수 있나요?


 

=================

위의 예를 제 상황에 맞게 변경하자면 

Item = 사용자 (계정정보)

Book = 소방사용자 (소방관련 정보 포함)

Movie = 의사사용자 (의사관련 정보 포함)

Album = 기타 사용자 (그외 필요 정보 포함)

 

로 둘수가 있겠죠.

 

그런데 시스템 로직상   소방사용자만 조회한다던가 의사사용자만 조회한다던가 하는 기능도 있을수 있지만

전체사용자를 계정정보 관련 소트로 불러온뒤 ( Item 리스트를 Item에 해당하는 소트로 불러온뒤)

소방사용자1, 소방사용자2, 의사사용자1, 소방사용자3,  의사사용자2   . ...  이런식으로 불러와야 되기때문에

List<사용자> 로 불러와야 되기도하고 

 

로그인, 계정정보수정과 같은 공통된 '사용자' 관련 기능들 구현시에도 추상클래스로 정의되었지만 '사용자' 객체를 가지고 접근해야 되는 상황이라고 사료됩니다.

 

이런 경우에도 상속관계가 맞는건지 아니면 다른 방법을 생각해야 되는건지 조차 햇갈립니다ㅠㅠ

 

 

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

네 다음과 같이 처리하시면 됩니다^^

// 리스트 조회할경우 ?
List<Item> itemList = itemRepository.findAll();   
for(Item item : itemList){
  instacneof book이면 로직 처리
  instacneof album이면 로직 처리
  ...
}

 

 

0

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

안녕하세요. 시큐웨어님

2가지 선택이 있습니다.

1. 프로필 정보가 쿼리의 where에 조건으로 들어가는게 아니라 단순히 데이터 참고용이라면 JSON으로 만들어서 문자로 저장하시는 것이 편리합니다. 추가로 JPA의 @Converter를 활용하면 편리합니다. (JPA 책 14.2 참고)

2. 꼭 테이블로 가야 한다면 다음을 참고해주세요.

https://www.inflearn.com/questions/14583

감사합니다.

시큐웨어님의 프로필 이미지
시큐웨어

작성한 질문수

질문하기