임베디드 타입 (복합 값 타입)

새로운 값 타입을 직접 정의해서 사용

@Entity
public class Member {

  @Id @GeneratedValue
  private Long id;
  private String name;

  @Embedded Period  workPeriod;
  @Embedded Address homeAddress;
  @Embedded PhoneNumber phoneNumber;
}

@Embeddable
public class Period {

  @Temporal (TemporalType.DATE) java.util.Date startDate;
  @Temporal (TemporalType.DATE) java.util.Date endDate;
}

@Embeddable
public class Address {

  @Column(name="city")
  private String city;
  private String street;
  private String zipcode;
}

@Embeddable
public class PhoneNumber {
  String areaCode;
  String localNumber;
  @ManyToOne PhoneServiceProvider provider;
  ....
}

@Entity
public class PhoneServiceProvider {
  @Id String name;
  ...
}

값 타입과 불변 객체

값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념이다. 따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.

값 타입 공유 참조

임베디드 타입 값은 값 타입을 여러 엔티티에서 공유하면 위험하다.

값 타입 복사

객체의 공유 참조는 피할 수 없다. 근본적인 해결책으로 가장 단순한 방법은 객체의 값을 수정하지 못하게 막으면 된다.

불변 객체

  • 값 타입은 될 수 있으면 불변 객체로 설계해야 한다.
  • 불변 객체를 구현하는 가장 간단한 방법은 생성자로만 값을 설정하고 수정자를 만들지 않으면 된다.

값 타입 컬렉션

@Entity
public class Member {
  ...
  @ElementCollection
  @CollectionTable(name = "FAVORITE_FOODS",
      joinColumns = @JoinColumn(name = "MEMBER_ID"))
  @Column(name = "FOOD_NAME")
  private Set<String> favoriteFoods = new HashSet<String>();

  @ElementCollection
  @CollectionTable(name = "ADDRESS",
      joinColumns = @JoinColumn(name = "MEMBER_ID"))
  private List<Address> addressHistory = new ArrayList<Address>();
  ...
}

@Embeddable
public class Address {

  @Column
  private String city;
  private String street;
  private String zipcode;
  ...
}

값 타입 컬렉션은 영속성 전이(Cascade) + 고아 객체 제거 기능을 필수로 가진다고 볼 수 있다.

값 타입 컬렉션도 조회할 때 페치 전략을 선택할 수 있는데 LAZY가 기본이다.

임베디드 값 타입 컬렉션 수정을 위해서 값 타입은 equals, hashcode를 꼭 구현해야 한다.

값 타입 컬렉션의 제약사항

  • 값 타입은 식별자라는 개념이 없고 단순한 값들의 모음이므로 값을 변경해버리면 데이터베이스에 저장된 원본 데이터를 찾기는 어렵다.
  • 이런 문제로 인해 값 타입 컬렉션에 변경 사항이 발생하면, 값 타입 컬렉션이 매핑된 테이블의 연관된 모든 데이터를 삭제하고, 현재 값 타입 컬렉션 객체에 있는 모든 값을 데이터베이스에 다시 저장한다.
    • ex) 회원 100번과 관련된 모든 주소 데이터를 삭제하고 현재 값 타입 컬렉션에 있는 값을 다시 저장한다.
  • 따라서 값 타입 컬렉션이 매핑된 테이블에 데이터가 많다면 값 타입 컬렉션 대신에 일대다 관계를 고려해야 한다.

정리

엔티티 타입의 특징

  • 식별자가 있다.
  • 생명 주기가 있다.
  • 공유할 수 있다.

값 타입의 특징

  • 식별자가 없다.
  • 생명 주기를 엔티티에 의존한다.
  • 공유하지 않는 것이 안전하다.

값 타입은 정말 값 타입이라 판단될 때만 사용해야 한다.

식별자가 필요하고 지속해서 값을 추적하고 구분하고 변경해야 한다면 그것은 값 타입이 아닌 엔티티다.

+ 따끈한 최근 게시물