스프링

[Spring Boot] Spring Data JPA - domain과 Entity 개념 / Entity에서 Dto 변환

imcoding 2022. 8. 24. 23:05

 

 

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에 반영되고, 다른 로직들에 영향을 미치게 된다.

 

따라서 위와 같이 엔티티 클래스를 사용하는게 바람직하다 볼 수 있다.