@Entity로 정의하는 객체
데이터가 변해도 식별자로 지속해서 추적 가능
int, Integer, String 처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체
식별자가 없으므로 변경시 추적 불가
자바 기본 타입, 래퍼 클래스, String
생명주기를 엔티티에 의존
공유하면 안된다.
기본 타입은 항상 값을 복사하고 래퍼 클래스는 공유 가능하지만 변경할 수가 없음
JPA에서 쓰이는 복합 값 타입.
새로운 값 타입을 직접 정의 한다.
@Embeddable : 값 타입을 정의하는 곳에 표시
@Embedded : 값 타입을 사용하는 곳에 표시
기본 생성자 필수
재사용 가능하고 응집도가 높다. 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있다.
임베디드 타입을 포함한 모든 값 타입은 값 타입을 소유한 엔티티에 생명주기를 의존한다.
DB에서 매핑되는 테이블은 임베디드 타입을 사용 전 후 둘다 같다. 엔티티의 값일 뿐이다.
객체와 테이블을 세밀하게 매핑하는 것이 가능하다.
@AttributeOverride : 속성 재정의 어노테이션. 한 엔티티에서 같은 값 타입을 사용할 때 사용해서 컬럼명을 재정의한다.
임베디드 타입의 값이 null이면 매핑한 컬럼 값은 모두 null이다.
값 타입을 여러 엔티티에서 공유하면 사이드 이펙트가 발생한다. 따라서 값을 복사해서 사용해야 한다.
하지만 객체 타입은 자바의 기본 타입과 다르게 참조 값을 직접 대입하는 것을 막을 방법이 없다. 즉, 객체의 공유 참조는 피할 수 없는 것이다.
따라서 이런 부작용을 원천 차단하기 위해 값 타입을 불변 객체로 설계해야 한다. 수정자를 만들지 않거나 private로 막아두어야 한다.
값 타입을 비교할때 equals() 메서드를 재정의 해서 동등성 비교에 성공해야 한다.
값 타입을 하나 이상 저장할 때 사용한다.
컬렉션 내부로는 기본 값 타입, 임베디드 타입만 가능하다
@ElementCollection, @CollectionTable 사용한다.
데이터베이스는 컬렉션을 같은 테이블에 저장할 수 없으므로 컬렉션을 저장하기 위한 별도의 테이블이 필요하다.
값 타입 컬렉션도 지연 로딩 전략을 사용해야 한다.
따로 설정하지 않아도 영속성 전이 + 고아 객체 제거 기능을 필수로 가진다.
// 값 타입 컬렉션 선언
@ElementCollection
// 테이블명 ADDRESS 설정
@CollectionTable(name = "ADDRESS",
// DB에 멤버의 PK가 들어가게 섫정
joinColumns = @JoinColumn(name = "MEMBER_ID")
)
private List<Address> addressHistory = new ArrayList<>();
값 타입은 식별자 개념이 없으므로 변경 시 추적이 어렵다
따라서 값 타입 컬렉션에 변경 사항이 발생하면 주인 엔티티와 연관된 모든 데이터를 삭제하고 값 타입 컬렉션에 있는 현재 값을 모두 다시 저장한다.
따라서 성능상 이슈가 생길 수 있다.
값 타입 컬렉션 대신에 일대다 관계를 위한 엔티티를 만들고 값 타입을 사용한다.
영속성 전이 + 고아 객체 제거를 사용해서 값 타입 컬렉션처럼 사용한다.
위의 코드를 바꿔 보자면
// AddressEntity 엔티티를 새로 만들어서 저장한다.
@OneToMany
private List<AddressEntity> addressHistory = new ArrayList<>();
엔티티와 값 타입을 혼동해서 엔티티를 값 타입으로 만들지 말자
식별자가 필요하고 지속해서 값을 추적하고 변경해야 한다면 엔티티로 만들자
단순할 경우 값 타입 컬렉션을 쓰고 아니면 엔티티로 만들자
일단 컬렉션 값 타입을 안쓴다고 생각하고 코드를 짜보자
출처 : 인프런 자바 ORM 표준 JPA 프로그래밍 - 기본편