엔지니어로 가는 길

JPA @Embedded, @Embeddable, @ElementCollection 그리고 FetchType 본문

프로그래밍/Java

JPA @Embedded, @Embeddable, @ElementCollection 그리고 FetchType

탐p슨 2020. 10. 2. 13:38
728x90

@Embedded와 @Embeddable

다음과 같은 상황을 생각해보자.

 

ToDo class

오늘 할 일 하나를 나타낸다.

 

TDL class

to-do-list를 나타낸다.

List<ToDo> 타입의 객체를 프로퍼티로 갖는다.

 

이때 db에 위와 같은 정보를 저장하고 싶다면 어떻게 해야 할까?

 

가장 먼저 떠올린 방법은 ToDo를 하나의 테이블에 매핑하고, TDL 또한 하나의 테이블에 매핑한 뒤 두 클래스를 One-To-Many와 Many-To-One 관계를 맺게 하는 것이었다. 하지만 생각해보니 ToDo 클래스는 항상 TDL 안에서만 존재하며, TDL을 부르지 않고 ToDo만 불러올 일이 없을 것 같았다. 그래서 ToDo를 TDL의 Embedded로 설정하였다. Embedded로 설정하는 방법은 다음과 같다.

 

 

ToDo에 @Embeddable을 붙인다. 다른 클래스의 Embedded 프로퍼티로 사용될 클래스임을 알리는 어노테이션이다. @Entity는 붙이지 않는다. Embedded이므로 독자적인 테이블을 갖지 않기 때문이다.

 

 

TDL에는 다음과 같이 ToDo 타입 프로퍼티 위에 @Embedded를 붙여준다. 이와 같이 하면 프로그램에서는 두 개의 클래스를 따로 두면서 데이터베이스에는 TDL 테이블 속에 ToDo의 모든 프로퍼티가 모두 들어가 있는 상태가 된다. 예를 들어 TDL에 '날짜' 프로퍼티가 있고, ToDo에는 '이름' 프로퍼티와 '우선순위' 프로퍼티가 있다면 데이터베이스에는 TDL의 테이블 속에 날짜, 이름, 우선순위가 모두 들어가게 된다.

 

 

 

@ElementCollection

만약 Embedded 삼고 싶은 프로퍼티가 Collection이라면 어떨까? ToDo는 그대로 두고, 아래와 같이 @ElementCollection을 붙이면 된다.

 

 

이 경우는 TDL 테이블에 ToDo가 모두 들어가는 것이 아니라, TDL은 순수한 TDL 상태 그대로 있고, TDL의 PK를 FK로 갖고 ToDo의 정보를 갖는 별도의 테이블이 하나 생성된다.

 

 

FetchType

*lazy: 필요할 때 가져오기

*eager: 바로 가져오기

 

이렇게 만들고 보니 lazy한 fetch가 가능한지 궁금했다. One-To-Many 관계일 경우에는 One을 데이터베이스에서 가져올 때 Many를 바로 가져오는 것이 아니라 필요한 시점에 lazy하게 가져오는 것이 가능한데, 지금 이 관계도 관계 속 두 객체가 모두 entity는 아니라는 차이점은 있지만 One-To-Many 관계이기 때문이다.

 

일단 아무 설정 없이 위의 상황에서 TDL만 가져와봤다.

 

 

 

디폴트로 lazy 타입이 설정되어 있다. 데이터베이스에 저장되기를 TDL은 ToDo에 대한 정보 없이 깨끗하게 저장되므로 TDL을 요청했을 때 TDL만 가져오는 게 자연스러운 것 같다. 확실히 하기 위해서 이번엔 가져온 TDL에서 ToDo 리스트에 대한 정보를 요청해보았다.

 

코드

 

발생한 쿼리

 

(한 번에 다 가져오는 것을 기대했는데 두 번의 쿼리를 날렸다. One-To-Many 관계였다면 한 번의 쿼리로 날렸을 것 같은데 이 부분은 나중에 기회가 된다면 확인해보도록 해야겠다.)

 

Fetch 타입을 EAGER로 설정해서 이젠 테스트해볼 차례다.

 

코드

 

코드

 

발생한 쿼리

 

EAGER답게 todo에 대한 어떤 요청도 하지 않고 TDL 객체만 가져다 달라고 요청했는데 left outer join으로 TDL 테이블에 ToDo에 대한 정보를 붙여서 가져왔다.

728x90
Comments