[Spring Boot] Spring Data JPA - domain과 Entity 개념 / Entity에서 Dto 변환
Entity를 공부하기 전에 먼저 도메인의 개념이 있어야 한다.
도메인을 잘 모르시는 분들은 더보기를 눌러 아래 글을 먼저 보시길 권장드립니다.
도메인(domian)의 사전적 의미는 영토, 분야, 영역, 범위 따위를 뜻한다.
소프트웨어 공학에서 도메인 모델이란, 특정 문제와 관련된 정보들을 저장하는 개념 모델을 말한다.
이 역시 어떤 "영역"(테이블)을 의미한다고 볼 수 있는데, 의미 자체가 다소 추상적이기 때문에 예를 들어보겠다.
우리가 계좌 관련 웹프로젝트를 진행한다고 했을 때 계좌 목록, 거래 목록 등을 저장해야 한다.
계좌 목록에는 계좌의 소유주, 계좌 번호, 현재 잔액, 생성 일자 등이 기록될 것이다.
거래 목록에도 비슷하게 금융 관련된 정보들이 기록될 것이다.
프로그래밍에서는 이를 데이터베이스 테이블에 저장함으로써 보관할 수 있다.
이렇듯 계좌 목록, 거래 목록과 같이 업무에 필요한 정보들을 쉽게 저장하고 관리하기 위한 집합을 도메인이라 설명할 수 있겠다.
도메인 클래스는 domain 패키지를 생성하고 그 안에 보관하는게 일반적이다.
그리고 우리가 원하는대로 업무에 필요한 정보들을 쉽게 저장하고 관리하기 위한 기능을 구현하기 위해서는 도메인을 엔티티 클래스로 만들어줄 필요가 있다.
간단하게 @Entity 어노테이션을 등록함으로써 엔티티 클래스로 만들어 사용할 수 있다.
쉽게 말해 엔티티 클래스가 도메인 클래스라고 봐도 무방하다.
Entity
그럼 Entity 어노테이션으로 도메인 클래스를 엔티티로 만들어보자.
엔티티 클래스는 DB 테이블과 매칭된다.
즉, DB 테이블을 자바 스프링 타입의 코드로 구현한게 엔티티 클래스다.
@Entity 어노테이션을 통해 엔티티 클래스를 만들 수 있다.
DB 테이블이 그렇듯 엔티티 클래스 역시도 필드, 프라이머리 키 등을 갖는다.
DBeaver 등의 DB 툴 없이도 엔티티 클래스의 필드에 값을 넣었다 뺐다 하며 우리가 원하는 프로그램을 만들 수 있는 것이다.
아래는 계좌 정보를 담는 엔티티 클래스다.
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Account {
@Id
@GeneratedValue
private Long id;
@ManyToOne
private AccountUser accountUser;
private String accountNumber;
@Enumerated(EnumType.STRING)
private AccountStatus accountStatus;
private Long balance;
private LocalDateTime registeredAt;
private LocalDateTime unRegisteredAt;
@CreatedDate
private LocalDateTime createdAt;
@LastModifiedDate
private LocalDateTime updatedAt;
위 클래스는 @Entity를 통해 엔티티 클래스로 선언되었다.
엔티티 클래스는 보통 @Builder 어노테이션과 함께 사용된다.
@Builder를 사용하면 필드에 필요한 값만 넣기가 수월하기 때문인데, 이를 포함하여 Entity의 부가적인 어노테이션들은 따로 다뤄보도록 하겠다.
Entity와 Dto 변환
Entity를 만들고 그 안에 필드값들을 만들어줬다면, 그 값은 서비스, 컨트롤러 등을 거치며 사용될 것이다.
여기서 주의할 점은, 엔티티의 값들을 엔티티 클래스의 것 그대로 가져와 사용하면 안된다는 점이다.
엔티티의 값이 변하면 Repository 클래스의 Entity Manager의 flush가 호출될 때 DB에 값이 반영되고, 이는 다른 로직들에도 영향을 미친다. 때문에 View와 통신하면서 일회성으로 데이터를 주고받는 Dto 클래스의 값으로 변환하여 사용해야 한다.
아래 코드를 보자.
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AccountDto {
private Long userId;
private String accountNumber;
private Long balance;
private LocalDateTime registeredAt;
private LocalDateTime unRegisteredAt;
public static AccountDto fromEntity(Account account) {
return AccountDto.builder()
.userId(account.getAccountUser().getId())
.accountNumber(account.getAccountNumber())
.balance(account.getBalance())
.registeredAt(account.getRegisteredAt())
.unRegisteredAt(account.getUnRegisteredAt())
.build();
}
}
Dto를 만들고 Account 엔티티 클래스를 받아 Dto 값으로 리턴하는 메서드를 구현했다.
이런식으로 엔티티의 값이 필요한 경우에는 Dto에서 @Builder로 값을 변환하면서 리턴해주는게 일반적이다.
만약 엔티티 값 그 자체를 반환해준다면, 엔티티 값을 받은 쪽에서 값에 변화를 줄 수 있게 된다. 그리고 그 값이 DB에 반영되고, 다른 로직들에 영향을 미치게 된다.
따라서 위와 같이 엔티티 클래스를 사용하는게 바람직하다 볼 수 있다.
끝