기록과 정리

JPA 값 타입이란? 본문

IT/JPA

JPA 값 타입이란?

zepetto 2022. 2. 14. 19:04

이 글은 김영한님의 자바 ORM 표준 JPA 프로그래밍 기본편 강의를 참고하였습니다.

www.inflearn.com/course/ORM-JPA-Basic/dashboard

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔

www.inflearn.com

 

JPA의 데이터 타입

JPA의 데이터 타입은 크게 2가지이다. 

 

1. 엔티티 타입

2. 값 타입

 

엔티티 타입은 @Entity로 정의하는 객체로 정의할 수 있으며 값 타입의 경우,  3가지로 분류할 수 있다.

 

1. 기본값 타입 

2. 임베티드 타입

3. 컬렉션 값 타입

 

 

1. 기본값 타입

기본값 타입 ( basic value type )의 경우 , int, double 같은 자바 기본 타입, 래퍼클래스 (Integer, Long) , String 을 예로 들수 있다.

Long과 String

Member 라는 엔티티안에 id 와 username을 이루는 Long , String이 기본값 타입이다. Member라는 엔티티에 의존적이다. 값타입의 중요하게 다루는 점이 있다면 공유되면 안된다는 점인데 기본 값의 경우 절대 공유될 수없다. 

int a = 10

int b = 20

a = b 라고 하면 b에 20이 복사가 되어 a로 넘어간다. 저장 공간이 복사되는 개념은 아니다.

 

2. 임베디드 타입

임베디드 타입 ( embedded type )의 경우, 직접 정의해서 사용하는 경우를 말하는데 임베디드 역시 직접 정의를 할뿐 int, String 타입으로 이루어진다. 기본생성자는 필수로 가져야하며 더불어 @Embeddable, @Embedded 이 두가지 어노테이션을 기억하자.

@Embedded
@Embeddable

Address라는 공통된 요소를 빼놓음으로써 조금더 객체지향적인 접근이 가능하며 , 엔티티가 더욱 의미있고 응집력이 높아진다.

강의에서는 둘중 하나는 생략에도 무관하다라고 설명하고 있다.

 

@Embeddable : 값 타입을 정의하는 곳

@Embedded : 값 타입을 사용하는 곳

 

임베디드 타입 역시 기본값 타입과 마찬가지로 엔티티 객체에 의존적이며 라이프 사이클도 엔티티객체를 따라간다.

@AttributeOverride

임베디드 값타입이 한 엔티티에서 중복이 될 경우 , @AttributeOverrid를 통해 재정의할 수 있다.  가령 직장 주소를 모아놓은 임베디드 값타입을 하나더 만들고 재정의가 가능하다.

 

임베디드 타입의 장점

  •  재사용성 
  •  높은 응집도
  •  값 타입별 의미있는 메소드를 만들 수 있다.

 

#Tip

값타입은 위에서 설명한대로 공유가 불가능하다. 이에 대하여 불변 객체 (immutable object)를 설계하여 사용할 것을 권장을 한다. 

 

불변객체란 선언과 동시에 수정을 할 수 없는 객체를 말하는데 Entity에 접근하지 못하도록 접근제한자 private 설정 또는 setter 메서드를 사용하지 않음을 말한다.

( 만약 불가피하게 변경해야한다면 변경해야할 대상에 들어갈 값을 재선언하여 새로 만들어서 등록하는 방식을 이용하자.)

 

또한 값타입을 비교할시에 동일성 비교 ( == ) 보다는 동등성 비교 ( equals )를 이용하여 비교한다. 각 엔티티 객체에 equals 메서드를 활용하도록하자.

Use getters during code generation

해당 체크를 통해 필드 직접 접근이 아닌 getter를 통하여 등등성 비교를 하도록 하자. 프록시 객체에 접근할 수 있도록 하여 비교가 가능하다.

3. 값 타입 컬렉션

값 타입을 하나 이상 저장시에는? 값 타입 컬렉션

 

@ElementCollection과 @CollectionTable 이 두가지를 사용했는데, @ElementCollection을 통해 값타입 컬렉션을 지정 ( 기본 fetch 전략은 지연로딩 lazy  ) 하고 @CollectionTable을 통해 해당 값타입 컬렉션이 사용할 테이블을 지정했다. 

 

DB에 테이블로 매핑할때 관계형 DB 컬럼에는 자바 컬렉션이 들어갈 수 없기 때문에 별도의 테이블을 만들어야한다.

 

 

테스트코드

해당 테스트 코드를 통해 em.persist하게 되면 member와 별개인 테이블을 가진 FavoriteFoods나 AddressHistory는 엔티티 객체 Member의 라이프 사이클을 따라 Persist 된다. ( 값타입 모두 엔티티의 라이프 사이클을 따른다. )

 

값타입 컬렉션의 경우 ,식별자라는 개념이 존재하지 않기때문에 수정시 하나의 로우만 수정하는 것이 아닌 해당 컬렉션의 주인 엔티티와 관련된 매핑된 테이블 로우를 전부 삭제하고 다시 저장을 하는 전략을 사용한다. 따라서 사용을 그리 추천하지 않는다. 대안책으로는 일대다 매핑을 사용하는 방법  (Cascade + orphan remove) 을 이용하여 값타입처럼 사용하는 방법이 존재한다.