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

Jinseok Han님의 프로필 이미지
Jinseok Han

작성한 질문수

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

Entity 메소드 파라미터로 DTO를 받는 것, 괜찮을까요?

작성

·

3K

2

1. 강의 내용과 관련된 질문인가요? 아니오
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예
3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예

[질문 내용]
안녕하세요?
JPA 수업 수강 후, 실제 업무에 적용하는 와중에 궁금한 점이 있어서 질문 남깁니다.
DB Update를 위한 Entity Method의 파라미터로 DTO를 받는 것이 프로그램 구동상에는 전혀 문제는 없는데요.
Domain driven design을 구현하는데에 있어서 엔티티 메소드의 파라미터로 DTO를 집어넣는게 바람직한 설계(?) 인지 문의 드립니다.
 
질문의 보다 빠른 이해를 위해 샘플 코드 및 시나리오를 아래와 같이 남깁니다.
 
- 상황 : 회원정보수정 API의 input으로 MemberDTO를 받음
- MemberDTO 내에 ContactDTO, List<AddressDTO>를 가진 구조 (Nested)
 
class MemberDTO {
...
private ContactDTO contactDTO;
private List<AddressDTO> addressDTO;
...
}
 
- Service 레벨에서 memberRepository.findById() 통하여 Member Entity를 불러옴.
- Member Entity와 Contact Entity은 1:1조인, Address Entity와는 1:N 조인
- Contact 및 Address 업데이트를 위해 Entity레벨에 다음의 메소드를 구현해두었으며, member.getContact().updateContact(contactDTO)로 해당 메소드를 호출
 
@Entity
class Contact(또는 Address) {
...
public void updateContact (ContactDTO contactDTO) {
...
this.phoneNumber = contactDTO.getPhoneNumber();
...
...
}
}
 
 
감사합니다.

답변 2

0

안녕하세요. Jinseok Han님, 공식 서포터즈 y2gcoder입니다.

저도 부족하지만 제 의견을 조심스럽게 말씀드려보겠습니다.

저는 호출부보다 메서드 선언부(엔티티 입장)에서 보시길 권해드립니다. 엔티티 입장에서는

@Entity
class Contact(또는 Address) {
...
public void updateContact (String phoneNumber, String email, String faxNumber, ...) {
...
...
...
}
}

이런 식으로 구현이 되어있다면 DTO가 수정되거나 삭제되는 것을 알 필요가 없어집니다. 하지만 반대로 기존처럼 DTO에 의존적이라면 DTO가 수정되면 엔티티도 수정되는 것은 필연이라고 생각합니다.

그런 점에서 위에서 말씀해주신 부분은 차이가 난다고 저는 생각합니다. ㅎㅎ

감사합니다.

Jinseok Han님의 프로필 이미지
Jinseok Han
질문자

답변 감사합니다.

메소드를 호출할때가 아닌, 엔티티 내 메소드 선언부 파라미터 입장에서 생각해보니 이해가 되네요.

 

부가적인 질문인데요. 혹시 엔티티에 수정해야할 필드 수가 상당히 많은 경우에도, 메소드 파라미터로 모든 필드를 넘겨받도록 코드를 짜는건 회피하기 힘들까요? 

(가령 회원 프로파일의 어트리뷰트가 대략 40-50개 된다는 가정하에..)

또한 40-50개 필드 중, 수정대상이 아닌 경우 기존값을 그대로 주는게 아니라 빈값으로 들어오는 케이스라면 (비즈니스 플로우 상 search 후, 수정/미수정 값 모두 채워서 update를 하는것이 아니고 수정 대상만 채워서 호출)

이 경우 아래처럼 조건문을 다 달다보니 보기에 지저분해보여 보다 깔끔한 패턴이 있을지 고민중에 있습니다.

if(name != null) this.name = name;

 

좋은 하루 보내세요.

1. Jinseok Han 님의 말씀을 들으니 그 상황이라면 저도 DTO의 사용을 고려해볼 것 같습니다. 대신 DTO를 생성한다면 위치를 엔티티와 같은 패키지에 둬서 패키지의 순환 참조가 일어나지 않게 할 것 같습니다. 

2. 저도 경험이 많지 않아 고민이 되는데요. 직장 동료가 질문을 한다면 JPA를 사용하고 있다면 어차피 dirty checking으로 엔티티를 업데이트할테니 각 필드별로 업데이트 로직을 작성하라고 할 것 같습니다. 그래야 테스트 코드를 짜서 검증할 때 하나씩 해볼 수 있어 더 명확하게 테스트를 할 수 있을 것 같고, 특정 필드를 검증하는 방법을 바꿀 때 좀 더 쉽게 찾을 수 있을 것 같기 때문입니다. 

파이팅입니다.

저도 실력이 많이 부족하지만 혹시나 도움이 될까하여 댓글을 추가로 달아봅니다~!



Jinseok Han 님의 케이스는 하나의 사용자가 가입을 하거나, 해당 사용자가 개인정보를 수정하는 것으로 보입니다.

이 케이스의 경우에는 어쩔 수 없이 거의 모든 파라미터가 해당 Entity 로 매핑이 되는 케이스 인 것 같습니다.

아래와 같은 케이스라면
Class User {

          @Embedded private Contact contact .. 혹은

          @OneToOne? private Contact contact ..

}

객체의 필드를 매핑하는 라이브러리를 사용해서,  아래와 같이 매핑을 하거나, dto 에서 Contact 로 매핑해서

Contact contact = 매핑라이브러리 사용 / Contact contact = dto.toContact()

갱신을 하는 방식을 사용하면 어떨까요?

user.updateContact(매핑라이브러리 사용(dto)); / user.updateContact(dto.toContact());

// 혹은 Contact 라는 객체를 생성하는부분이 복잡한 로직이거나, 외부호출 등 의존성이 필요하다면 팩토리클래스 혹은 팩토리메서드를 만드는것도 고려하실 수 있을 것 같아요

 

물론 DTO 는 데이터를 전달하는 역할만 수행하는게 맞고, 위에서 말한 dto 를 Contact 로 매핑하는 방식은 올바르지 않을 수 있지만 어느선에서 타협하신다면, Entity 의 update 메소드에서 DTO 를 전달하는 것보다 고수준모듈을 지키는 방식이 되지않을까합니다.

 

해당 방식을 사용하신다면, Request 의 변화에 대해서 도메인레이어에서는 영향을 받지않는 설계가 가능할 것 같습니다.

 

저는 개인적으로 DTO 를 Entity 와 같은 패키지에 두는것 보다는, 위처럼 매핑을하는 방식이 더 좋지않을까 생각합니다.

1. DTO 를 바로 전달하게 된다면 위에 설명하신 것처럼 DTO 의 phone 라는 필드가 phoneNumber 로 변경되는 경우, Entity 코드또한 수정이 일어날 수 있다고 생각하고,

2. 등록과 수정에서 다른 DTO 를 사용하신다면 updateContact(RegisterDTO dto), updateContact(UpdateDTO dto) 처럼 update 하는 코드가 지속적으로 늘어날 수 있지않나 하는 우려가 듭니다.

 

RequestDTO 는 서버와 클라이언트의 규약일 뿐이라고 생각합니다. 따라서 비즈니스의 핵심규약을 모아놓은 도메인레이어에 Entity 와 같이 위치하는 것은 개인적으로 좋은 설계가 아니지 않나 생각이 드네요.. 

 

제가봐도 글을 잘 못썼지만.. 이해하시는데는 문제가 없지않을까 .. 하네요 T^T

그럼 20000,,

감사합니다.
말씀하신 것처럼 DTO에서 entity로 바로 매핑하는 것도 있는데 그걸 생각못했네요.
저도 DTO에서 entity로 변환해주는 게 좋아보입니다.

0

Jinseok Han님의 프로필 이미지
Jinseok Han
질문자

답변 감사합니다 이석준님,

말씀해주신 부분이 바로 질문의 배경이었습니다. Entity 내 메소드의 파라미터로 RequestDTO를 받게 되면, DTO 변화에 따른 Entity (Low-level 데이터)가 영향을 받는 것, 즉 엔티티가 DTO에 의존하게 되는게 아닌가? 에서 출발한 질문입니다.

그럼에도 질문 드린 이유는, 제가 보기에 다음 메소드를 호출하는데에 DTO로 파라미터를 넘기는 것과, DTO를 구성하는 필드값들로 파라미터를 넘기는 것이 Entity-DTO 레이어간에 의존도 방향에 대해 과연 차이가 있을까 라는 의문은 아직 잘 확 와닿지가 안되네요. 결국 DTO의 변경에 따라 전/후 모두 Entity가 영향을 받는건 동일한게 아닌가 싶기도 하구요.

 

1. updateContact(contactDto)

 

2. updateContact(contactDto.getPhoneNumber, contactDto.getEmail, contactDto.getFaxNumber, ...)

Jinseok Han님의 프로필 이미지
Jinseok Han

작성한 질문수

질문하기