[스프링/Spring] 연관관계를 갖는 DTO를 엔티티로 저장할 때 고민

kindof

·

2021. 10. 3. 21:35

💡 문제 상황

만들어보고 있는 프로젝트에서는 '유저', '게시물', '카테고리'라는 도메인이 존재합니다. 이 때 유저와 게시물은 일대다관계, 카테고리와 게시물도 일대다관계를 가지고 있는데요. 다른 도메인이나 서비스에 대한 로직은 차치하고 말씀드리겠습니다.

 

문제가 되는 상황은 사용자가 게시물을 작성하는 상황에서 발생했는데요.

 

아래는 게시물 작성과 관련된 Controller, Service, Post 엔티티, PostSaveDTO입니다. PostSaveDTO는 게시물을 작성할 때 JSON 데이터를 객체로 입력받아 서비스 로직에 던져지는 녀석입니다.

@Controller
@Service
Post 엔티티
PostsSaveRequestDto

문제는 어떤 사용자가 게시물을 작성한다고 가정했을 때, Json 형태로 받아올 수 있는 정보는 유저 정보, 카테고리의 아이디, 게시물의 제목과 내용이라는 점에서 생기는데요.

 

위와 같이 DTO가 Category 자체를 멤버변수로 가지고 있게 되면 카테고리 아이디만을 받아서는 카테고리와 직접적으로 매핑이 안됩니다.

 

왜냐하면 사용자가 카테고리 자체의 정보를 모두 입력할 수는 없다고 생각했기 때문인데요. 자바스크립트로 카테고리를 선택하는 셀렉트 박스에 카테고리 아이디와 카테고리 이름을 매핑해주는 방식을 이용했기 때문입니다.

 

🤔 1. 고민(1)

이 때, 유저의 정보는 컨트롤러에서 로그인 유저의 세션 정보를 이용해 그대로 입력받으면 된다고 생각했고, 카테고리의 매핑에 대해서는 카테고리 아이디를 전달받은 후에 카테고리 레포지토리를 조회해서 해당 카테고리를 Post에 매핑을 해주는 로직이 필요하다고 생각했습니다.

 

그래서 아래와 같이 코드를 수정했습니다.

@Controller

Controller에서는 현재 세션 유저의 이름을 requestDto의 userName으로 지정해줍니다. 

@Service

그리고 서비스 로직에서 현재 requestDto에 저장된 userName을 바탕으로 해당 유저를 레포지토리에서 찾고, User를 매핑해줍니다.

DTO

DTO는 위와 같이 변경했는데요. userName과 User에 대한 setUser()를 오버로딩해서 구현했습니다.

 

JSON으로 전달되는 데이터만을 가지고 DTO를 빌드하고, 컨트롤러에서 유저의 이름을 매핑하고 서비스 로직에서 유저와 카테고리의 정보를 매핑했습니다. 그리고 최종적으로 User, Category, title, content를 갖고 있는 DTO를 엔티티로 생성하여 레포지토리에 저장했습니다.

 

이렇게 로직을 수정하고 자바스크립트는 사용자에게 category_id, title, content의 정보만 받아서 fetch() API를 이용해 POST 요청을 보내도록 했습니다.

 


나름 열심히 생각해서 문제를 해결하긴 했지만 많은 찝찝함이 남는 것 같습니다.

 

우선 DTO를 설계하는 관점에서 어떤 멤버변수들이 필요할까에 대한 고민을 하지않고 만든 것이 아쉬웠고, DTO에서 Setter를 통해 필요한 내용을 매핑하는 과정이 뭔가 깔끔하다고 느껴지지 않았습니다. 서비스 로직에 DTO를 던질 때, 해당 로직에서 필요한 형식으로 DTO를 만들어야한다고는 생각했지만, 이 방법이 최선인지에 대한 의문이 남았기 때문이죠.

 

아마 스프링을 좀 더 공부하고 경험하다보면 위와 같은 문제를 더 적절하게 해결하는 방법을 배우리라 생각합니다.

 

나중에 코드를 다시 리팩토링하면서 이런 부분을 수정해봐야겠습니다. 

 

 

 

* 2021. 10. 25

이 글을 지금 다시 읽어보니, DTO 설계가 완벽히 잘못됐다고 생각이 듭니다. 애초에 Post DTO에는 카테고리 자체가 들어갈 필요가 없는 것 같습니다. 카테고리 아이디만을 받아서 포스트 엔티티를 생성하고, 서비스 로직에서 포스트 엔티티의 카테고리를 넣어주면 될 것 같습니다. 나중에 다른 글로 정리해봐야겠습니다.