본문 바로가기
Spring & Spring Boot

[Spring] DTO vs Entity vs VO

by wook99 2024. 11. 7.

오늘은 DTO와 Entity, 그리고 유사 개념이지만 다른 VO의 개념들과 차이에 대해서 정리해보았다.

잘 구분해서 사용하려고는 하지만, 사실 정확한 개념을 설명하라고 하면 자신있게 대답하지 못했다.

이 포스팅을 바탕으로 확실하게 머릿속에 정리해야겠다.


DTO

  • DTO는 Data Transfer Object 의 약자이며, 데이터 전송 객체라는 의미를 가지고 있다.
  • 데이터 교환만을 위해 사용하는 객체이며, 비즈니스 로직을 갖지 않고, getter/setter 메소드만 갖는다.
  • Controller와 같은 클라이언트와 직접 마주하는 계층에서 DTO를 사용하여 데이터를 요청 / 응답한다.
  • setter 를 가지는 경우 가변 객체로, 가지지 않는다면 불변 객체로 사용할 수 있다.
  • 불변 객체는 setter대신 생성자를 이용하여 초기화할 수 있겠다.
@Getter
@Setter
public class UserDto {
    private String name;
    private Integer age;
    private Timestamp birth;
}

 


Entity

  • 실제 DB 테이블과 매핑되는 핵심 클래스. DB 테이블에 존재하는 컬럼들을 필드로 가지는 객체이다.
  • DB 테이블 내에 존재하지 않는 필드를 가지면 안된다.
  • 비즈니스 로직을 포함할 수 있다.
  • Entity는 DB 영속성의 목적으로 사용되는 객체이며, 요청과 응답 값을 전달하는 클래스로 사용하는 것은 좋지 않다.
  • 외부에서 Entity 클래스의 Data Field에 접근하지 못하도록 제한해야 한다.
  • 변경되면 안되는 인스턴스나 데이터에 대해서 setter를 통해 접근이 가능해지기 때문에 setter 사용을 지양한다.
    • 대신 생성자 또는 Builder를 사용한다.
@Entity
@Builder
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class User{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String name;
    
    @Column(nullable = false)
    private Timestamp birth;
}

VO

  • Value Object의 약자로, 값 그 자체를 표현하는 객체이다.
  • equals()와 hashCode()를 오버라이딩 하여 객체의 불변성을 보장한다. 
    즉, 객체들의 주소 값이 달라도 데이터 값이 같으면 동일한 것으로 판단한다.
  • ReadOnly의 특징을 가지고 있어 getter는 가질 수 있지만, setter는 가지지 않는다.
  • 비즈니스 로직을 포함할 수 있다.

 

@Getter
@AllArgsConstructor
public class UserVo {

    private String name;
    private Integer age;
    private Timestamp birth;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserVo userVo = (UserVo) o;
        return Objects.equals(name, userVo.name) && Objects.equals(age, userVo.age) && Objects.equals(birth, userVo.birth);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age, birth);
    }
}

 


VO vs DTO

둘 다 데이터를 담고 있는 객체이다. 하지만 차이점이 있다.

  • VO는 Read Only의 목적이 강하고, 데이터 자체도 불변하게 설계한다.
  • DTO는 주로 데이터 수집의 용도가 더 강하다.

 


VO vs Entity

DTO와 VO는 데이터를 담고, 다른 계층으로 데이터를 넘겨주기 위한 자료구조이다.
따라서 어떠한 기능 및 동작이 없어야 한다.

 

반면, Entity는 핵심 비즈니스 로직을 담는 비즈니스 영역의 일부이다. 

따라서 컴포넌트들 사이에서 데이터 전달을 위한 객체로 사용하지 않는다.


DTO vs Entity

여러번 언급 했듯, DTO는 데이터를 전송하기 위한 용도로 쓰여야 한다.

 

엔터티와 달리, DTO는 데이터베이스와 직접 연결되지 않는다. 특정 데이터만 선택하여 전달하거나 계산된 결과를 포함하여 클라이언트에 반환할 때 주로 사용된다.

 

엔터티는 데이터베이스의 실제 데이터를 저장하고 관리하는 역할을 하며, 애플리케이션의 비즈니스 로직과 데이터베이스 사이의 매핑을 책임진다.

 


참고

 

Spring에 JPA를 쓰는 경우에는 Entity라고 표현하고, MyBatis를 쓰는 경우에는 주로 VO(ValueObject)라고 표현한다.

 

그 이유는 JPA는 ORM이고 MyBatis는 SQL-Mapper이기 때문이다.
ORM은 SQL문이 아닌 RDB 객체를 자바 객체로 매핑하며 객체간 관계나 식별자를 가질 수 있다.
반면에 SQL-Mapper는 SQL문으로 RDB에 접근하고 데이터를 객체로 매핑하며 객체간 관계나 식별자는 가질 수 없다.

때문에 JPA에서는 식별자를 가지는 Entity, MyBatis에서는 값 객체를 의미하는 VO라는 명칭을 사용한다.