본문 바로가기

MY개발생각

[개발생각] jpa에서 조인 Entity를 사용하는 신박한 방법

JPA에서 엔티티에 관계설정을 하지 않고, 조인을 유연하게 사용하는 방법은 뭐가있을까?

 

 

정답은 아니지만, 오늘 좀 신박한 방법을 하나 생각해내서, 공유를 해본다.

 

User, Group 엔티티가 존재한다고 해보자!

User의 id와 Group의 userId로 조인해서, User정보와 Group정보를 합쳐서 사용해야한다.

(Jpa에서 관계설정 방법은 지양하는 전제조건이다)

 

이럴때, 아래와 같이도 할수있겠다고 생각했다.

(이런생각 한사람이 많을까? ㅋ.. 좀 정상아닌것 같기도 하지만.. 구현해보니 나름 장점이 많다)

//UserRepository.kt
interface UserRepository : JpaRepository<User, Long> {

   @Query("
        SELECT u, g FROM User u, Group g 
        WHERE u.id = g.userId And u.id = :userId      
   ")
   findUserAndGroupInfo(userId:Long) : Pair<User, Group>
}

//UserMapper.kt
Pair<User, Group>.toDto() : UserDto {

  val user = this.first
  val group = this.second
  
  return UserDto(
         userId = user.id,
         name = user.name,
         groupName = group.groupName
   )
}

 

일반적으로는, @Query에서 리턴값을 UserDto로 바로 받는 방법을 많이 쓴다. 아래와 같은 방법 말이다.

 

//UserRepository.kt
interface UserRepository : JpaRepository<User, Long> {

   @Query("
        SELECT UserDto(u.id, u.name, g.groupName) 
        FROM User u, Group g 
        WHERE u.id = g.userId And u.id = :userId      
   ")
   findUserAndGroupInfo(userId:Long) : UserDto
}

 

그런데 여기서 위와 같은 Query구문은 사용할수가 없다.

JPA에서 UserDto를 바로 찾지를 못하기 때문이다.

(Entity package가 아니기에, jpa에서 UserDto클래스를 알수가 없어서, 단순하게 클래스명만으로는 사용/주입 할수없다)

//UserRepository.kt
interface UserRepository : JpaRepository<User, Long> {

   @Query("
        SELECT new com.example.dto.UserDto(u.id, u.name, g.groupName) 
        FROM User u, Group g 
        WHERE u.id = g.userId And u.id = :userId      
   ")
   findUserAndGroupInfo(userId:Long) : UserDto
}

 

이렇게 new com.example.dto.UserDto(xxxxx) 풀패키지명을 Query문에 써줘야한다..

그런데 이게 문제가 뭐냐면,

만약 UserDto의 패키지를 이동하거나 삭제하거나, 수정했을때,

저 쿼리구문을 모두 찾아서 풀패키지명을 수정해줘야한다는 것이다...

별것 아닌것 같지만,

유지보수에 너무나도 단점으로 다가온다.

 

이런 이유로 처음 방법을 생각해봤다.

 

Entity를 그냥 Pair클래스로 결과로 받고,

해당 2개의 Entity 결과(User, Group)를 toDto 변환하는 확장함수를 만들어서 toDto함수로 변환할때,

직접 맵핑을 해서 UserDto를 만드는 방법이다.

 

엔티티를 toDomain()으로 변환하는 Mapper는 DDD에서는 필수로 있어야하는 요소이기도 해서,

Mapper에서 Dto클래스에 담아주게 관리를 한다면, 관리측면이나, DDD측면에서도 훨씬 장점이 많다.

바로 User, Group엔티티를 이용한 복합 Domain Class로 변환도 가능해서 훨씬 유연해진다.

 

이 방법은 앞으로 자주 사용하자!!!! (아니면 위와같은경우는 과감하게 QueryDsl을 사용하자!)

단점이 없다!!! 완.벽.해!!!!