천천히 알아보는 코딩공부

[spring] DTO, Entity 차이 및 전달 로직 본문

Java/SpringBoot

[spring] DTO, Entity 차이 및 전달 로직

고기고기물고기 2022. 12. 1. 16:56

 

Entity는 Controller, Client단에서 쓰이면 직접 쓰이면 좋은 설계가 아니라고 한다.

Entity는 Service -> Repository -> DB 상태로만 사용하는 것 같다.

 

Entity

DB에 저장하기 위해 유저가 정의한 클래스

실제 DB테이블과 매칭

@Getter
@NoArgsConstructor
@Table(name="admin")
@Entity
public class Member {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private long id;

    private String name;

    private String password;
    
    private String email;
    
}

 

 

DTO

데이터 전송 객체

DB에서 데이터를 얻어 Service나  Controller등으로 보낼때 사용하는 객체

@Getter
@NoArgsConstructor
public class UserDto {
    private String name;
    private String password;
    private String email;
}

 

 

그러면 DTO  Entity 바꿔주기 (빌드 패턴 사용시)

@Getter
@NoArgsConstructor
@Entity
public class User {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private long id;

    private String name;

    private String password;
    
    private String email;
    
    @Builder
    public User(String name, String password, String email) {
        this.name = name;
        this.password = password;
        this.email = email;
    }
}

 

Dto class에 toEntity 함수를 정의해서 entity로 바꾸는 기능 추가하자!

@Getter
@NoArgsConstructor
public class SaveRequestUserDto {
    private int id;
    private String name;
    private String password;
    private String email;
    
    @Builder
    public SaveRequestUserDto(int id, String name, String password, String email){
        this.id = id;
        this.name = name;
        this.password = password;
        this.email = email;
    }
    
    //dto -> entity
    public User toEntity(){
        return User.builder()
                .id(id)
                .name(name)
                .password(password)
                .email(email)
                .build();
    }
}

 

Dto class에 생성자를 만들때 파라미터를 entity로 넣으면서 매핑된 Dto를 만들수 있다. (DB를 조회할때 쓰임)

@Getter
@NoArgsConstructor
public class ResponseUserDto {
    private int id;
    private String name;
    private String password;
    private String email;
    
    //entity -> dto
    public ResponseUserDto(User entity){
        this.id = entity.id;
        this.name = entity.name;
        this.password = entity.password;
        this.email = entity.email;
    }
}

 

*Entity는 Setter를 만들면 안된다고한다.

Setter를 무분별하게 사용하다보면 여기저기서 entity값을 변경할수 있기 때문에 일관성을 보장할수 없다.

의미있는 변경 메소드이름을 사용한다.

(DB update할때 쓰임)

@Getter
@NoArgsConstructor
@Entity
public class Member {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private long id;

    private String name;

    private String password;
    
    private String email;
    
    //Setter를 사용하지 않고 의미있는 메소드를 사용하여 변경
    public void passwordAndEmailUpdate(String password, String email){
        this.password = password;
        this.email = email;
    }
    
}

 

참고사항

 

질문

 

안녕하세요 정말 유익한 강의 잘듣고 있고요 항상 친절한 답변에 감사함을 느낍니다.

1.create시 createDto로 서비스로 넘어 온다면 아래에 방법중 어떤게 유지보수와 같은 측면에서 가장 나은 선택인가요?

a.  model mapper 나 mapstruct 라이브러리로 매핑한다.

b. 서비스 계층에서 엔티티 빌더로 dto 값을 하나하나 세팅한다.

c. 엔티티 생성자나 빌더에 dto 를 넘기고 그안에서 값을 세팅한다.

2.update시 updateDto로 서비스로 넘어 온다면 아래에 방법중 어떤게 유지보수와 같은 측면에서 가장 나은 선택인가요?

a.강의에서 처럼 dto 값을빼서 전달한다. entity.change(updateDto.getA(),updateDto.getB())

b. 전체 Dto를 넘긴다. entity.change(updateDto)

3. update patch시에는 변경하지 않는값은  updateDto에 널로 들어온다면  모든 값을 하나씩 체크하면서 null 이 아닌것에대한 엔티티를 업데이트 해주는 방식이 최선인가요?

 

4.만약 엔티티에서 dto 로 변환시에는 보통 어떤 방식으로 실무에서 많이 하나요?

 

답변

 

안녕하세요. asdkfur님 좋은 질문입니다.

1번 먼저 답을 해드리면

a,b,c 모두 정답입니다. 저는 개인적으로 model mapper를 선호하지 않지만, 주변에서 사용하는 것을 말리지는 않습니다^^

답을 드리면 생성자를 사용하는게 좋은가? 빌더를 사용하는게 좋은가? 별도의 생성자용 static 메서드를 사용하는게 좋은가? 아니면 별도의 생성 클래스를 만들어서 여기에서 생성해 주는게 좋은가? 등등 여러가지 상황이 있습니다.

결국 모두가 정답이기에 제가 선호하는 기준을 말씀드리면, 가장 단순한 방법부터 생각합니다. 만약 생성 로직이 정말 단순한 객체라면 그냥 생성자를 쓰는게 편합니다. 그런데 생성할 때 뭔가 비즈니스 로직이나 의미있는 생성자 메서드 명이 필요하다면 생성자용 static 메서드를 사용합니다. 만약 파라미터가 너무 많거나 복잡하면 빌더를 사용합니다. 이런식으로 상황에 맞는 방법을 잘 선택하는게 중요합니다. 결국 상황에 따라서 복잡도를 높이지 않는 선에서 단순한 방법을 선택하는 것이 좋은 방법이라 생각합니다.

2번도 같은 방법으로 선택하시면 됩니다. 파라미터로 넘기면 아무래도 재사용성이 좋아집니다. DTO를 넘기면 편하지만, 해당 엔티티가 DTO에 의존하게 됩니다. 그래도 파라미터가 너무 많으면 update용 dto를 만드는 것을 고려하는 것이 좋습니다.

3번은 null 체크를 하면서 아닌 것에 대한 업데이트를 해야합니다.

4번은 이번 강의에서 보여드린 모든 방법을 사용합니다. 1번의 답과 마찬가지로 model mapper를 사용하기도 하고, 직접 한땀한땀 필요한 값을 꺼내서 DTO로 변환하기도 합니다. 또는 JPQL에서 DTO로 바로 변환하기도 하구요. 딱 한가지만 조심하면 되는데, 절대 엔티티가 View용 DTO를 의존하면 안됩니다. 반대로 View용 DTO가 엔티티를 의존하는 것은 괜찮습니다.

다 장단점이 있어서 고민이 쉽지 않을 때가 있는데요. 저는 나름 다음과 같은 방법을 사용합니다.

1. 가장 쉬운 방법을 선택한다. (머리속으로 생각이 도는 것 보다 일단 가장 쉬운 방법으로 진행하는 것을 추천합니다.)

2. 직접 코드를 작성해본다. (머리속으로 생각이 도는 것 보다 일단 짜보면 쉽게 풀릴 때가 많습니다. 그리고 그 상황에 따라서 더 나은 코드가 있습니다.)

3. 의존관계를 생각한다. (의존관계가 복잡해지면 잘못된 코드입니다.)

도움이 되셨길 바라며^^ 감사합니다.

 

 

출처 : jpa create 및 update 시 dto에서 entity 변환방식 - 인프런 | 질문 & 답변 (inflearn.com)

 

lombok builder annotation - 인프런 | 질문 & 답변 (inflearn.com)

modelMapper에 대해 질문하고 싶습니다! - 인프런 | 질문 & 답변 (inflearn.com)

 

-- 어노테이션 정리

 

https://daeseok94.tistory.com/64

 

[Spring] Lombok 자주 사용하는 어노테이션 정리

@Getter/@Setter 필드에 @Getter나 @Setter를 붙인다면, lombok이 해당 필드에 대한 기본 getter/setter를 생성해줍니다. @Getter @Setter public class BoardDTO { // TB_BOARD private Long idx;// 번호(PK) private String title;// 제목 pr

daeseok94.tistory.com

 

Comments