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

roman14님의 프로필 이미지
roman14

작성한 질문수

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

회원 수정 API

엔티티의 필드가 많을 때 업데이트 방법?

작성

·

1.1K

3

API 개발 기본 - 회원 수정 API

해당 강의 시리즈를 들으며 전 강의부터 생겼던 궁금한 사항에 대해 질문을 드립니다.

 

예제의 경우는 최대한 간단하게 간소화시킨 엔티티를 예시로 들었지만, 필드가 많은 엔티티의 경우에는 어떤 방식으로 업데이트를 하는지 감이 잡히질 않네요.

 

// java
@RequestMapping(value = "/v1/edit/{memberId}", method = RequestMethod.PUT)
public EditMemberResponse editMemberV1(@PathVariable Long memberId, @RequestBody @Valid EditMemberRequest request)
{
  memberService.update(memberId, request.getName());
  ...
  return new EditMemberResponse(member);
}

강의 내용 중 위와 같이 업데이트 파라미터에 DTO 필드를 받아 업데이트 하도록 서비스를 작성하셨는데, 단순히 이름만 있는 엔티티 클래스가 아닌 필드가 굉장히 많은 엔티티의 경우에는 어떤식으로 업데이트 처리하는 것이 효율적일지 궁금해서 질문을 드립니다.

 

@Entity
public class Temp {
  @Id @GeneratedValue
  private Long id;
  private String field01;
  private String field02;
  // ...무수히 많은 필드들
  private String field66;
  private String field67;
}

 

예를들어, 위와 같은 Temp 클래스의 경우를 업데이트 하기 위해 앞서 설명한 방식으로 업데이트 기능을 서비스계층에 구현한다면 아래와 같이 실질적으로 사용이 불가능할정도로 가독성과 생산성이 떨어졌습니다.

// java
tempService.update( editTempRequest.getField01(), editTempRequest.getField02(), editTempRequest.getField03(), editTempRequest.getField04(), ..., editTempRequest.getField67() );

 

아래와 같이 서비스 계층에 EditTempRequest DTO 계층 클래스를 직접 넘기는 방법도 생각을 해보았습니다만, 서비스 계층에서 DTO 클래스를 이용하기 위해 컨트롤러 계층에서 이너 클래스로 선언된 DTO를 별도의 public 클래스로 선언해주어야 되므로 별도의 자바 파일과 패키지를 구성하게 되어 불필요한 복잡도가 증가하는 문제가 발생했습니다. 또한, 단순히 요청, 응답을 위해 데이터를 담는 목적으로 사용되어야 하는 DTO 클래스의 역할과 책임이 확장되는 문제도 생겼습니다.

// java
import com.wahhahaha.controller.dto.editTempRequest;

...

tempService.update( editTempRequest );

 

클라이언트 측에서 수정 API를 호출하기 전에 조회 API를 우선 호출하여 각 필드 정보를 가진 상태로 전체 필드를 이용한다면 merge 업데이트로 쉽게 해결이 가능하겠다라는 생각을 해보긴 했지만 merge는 가급적 이용하지 않는 편이 좋다는 전 강의 내용이 있어 혼란스럽네요.

답변 2

4

안녕하세요. roman14님, 공식 서포터즈 David입니다.

아래와 같이 서비스 계층에 EditTempRequest DTO 계층 클래스를 직접 넘기는 방법도 생각을 해보았습니다만, 서비스 계층에서 DTO 클래스를 이용하기 위해 컨트롤러 계층에서 이너 클래스로 선언된 DTO를 별도의 public 클래스로 선언해주어야 되므로 별도의 자바 파일과 패키지를 구성하게 되어 불필요한 복잡도가 증가하는 문제가 발생했습니다. 또한, 단순히 요청, 응답을 위해 데이터를 담는 목적으로 사용되어야 하는 DTO 클래스의 역할과 책임이 확장되는 문제도 생겼습니다.

 

만약 단순 요청, 응답을 위한 DTO를 서비스단까지 내려오게 하고 싶지 않다면 서비스단에서 단순 업데이트용으로 사용하는 DTO(예: TempUpdateDto)를 만들어도 무방할 것 같습니다.

물론 이렇게 되면 컨트롤러에서 사용되는 DTO, 서비스에서 사용되는 DTO로 나눠지겠지만요.

 

클라이언트 측에서 수정 API를 호출하기 전에 조회 API를 우선 호출하여 각 필드 정보를 가진 상태로 전체 필드를 이용한다면 merge 업데이트로 쉽게 해결이 가능하겠다라는 생각을 해보긴 했지만 merge는 가급적 이용하지 않는 편이 좋다는 전 강의 내용이 있어 혼란스럽네요.

 

저는 조회한 뒤 변경감지로 처리하는 편이며 수정 로직은 아래와 비슷합니다.

change(Member member) {
if (Objects.nonNull(member.name)) {
  this.name = member.name;
}}

 

이와 별개로 벌크성 업데이트의 경우 꼭 변경감지로 처리하지 않아도 됩니다. 아래 글을 참고해주세요.

https://github.com/jojoldu/blog-comments/issues/318#issuecomment-617598001

감사합니다.

0

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

 

  • 보통 한 엔티티에 많은 필드가 들어간다면 정규화가 잘못된 엔티티일 가능성이 높고, 보통 테이블의 컬럼이 15개 이상 넘어가는 경우가 없으므로 수고스럽더라도 더티 체킹을 통해 업데이트를 구성하는 것이 좋다.

일단 엔티티의 필드가 많다면 잘못 정규화된 엔티티일 수 있으니 그 가정은 불필요하다 생각되어 넘기게 되었고, 좀 수고스럽더라도 답변주신 내용처럼 각 필드마다 들어온 값을 하나하나 확인해서 값이 있을 경우 변경 처리하는 방법이 가장 이상적인 것 같습니다.

하지만 컨트롤 계층에서 서비스 계층으로 변경되어야 할 정보들이 전달되어야 가능한 이야기인데, 말씀하신대로 서비스 계층에서 사용될 DTO 클래스를 생성하는 방법 외에 좀 더 나은 방법이 없을까요? 여전히 제가 질문했던 것과 같은 즉 아래와 같은 이슈가 생기는 것 같습니다.

아래와 같이 서비스 계층에 EditTempRequest DTO 계층 클래스를 직접 넘기는 방법도 생각을 해보았습니다만, 서비스 계층에서 DTO 클래스를 이용하기 위해 컨트롤러 계층에서 이너 클래스로 선언된 DTO를 별도의 public 클래스로 선언해주어야 되므로 별도의 자바 파일과 패키지를 구성하게 되어 불필요한 복잡도가 증가하는 문제가 발생했습니다. 또한, 단순히 요청, 응답을 위해 데이터를 담는 목적으로 사용되어야 하는 DTO 클래스의 역할과 책임이 확장되는 문제도 생겼습니다.

 

답변 감사합니다!

 

별도의 자바 파일과 패키지를 구성하게 되어 불필요한 복잡도가 증가

 

이 부분은 당장 다른 방법이 떠오르진 않네요ㅎㅎ DTO관점에서 불필요한 복잡도 증가라기 보다 엄격한 레이어 구분으로 인해 발생하는 약간의 부작용 정도로 생각됩니다.

roman14님의 프로필 이미지
roman14

작성한 질문수

질문하기