CH09 값 타입
값 타입이 뭔가 싶지만 초반에 엔티티 매핑에서 테이블 단위의 매핑을 했다면 이번에는 컬럼 단위의 매핑에 관한 내용이었다. 어떻게 매핑한다는 내용보다는 Object 관점에서 일반적으로 사용하는 컬럼의 타입 말고 조금 더 세밀한 객체 모델링을 할 수 있는 방법에 대해서 다뤘다.
실무에서 많이 사용해온 부분이라서 엄청 자세하게 정리할 필요까지는 없을 것 같지만 기본적인 내용들은 정리를 하려고 한다.
@Embedded, @Embeddable
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
//period
@Embedded
private Period period;
//address
@Embedded
private Address homeAddress;
}
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
public Address() { // 기본생성자 필수
}
}
@Embeddable
public class Period {
private LocalDateTime startDate;
private LocalDateTime endDate;
public Period() { // 기본생성자 필수
}
}
당연한 이야기지만 @Embeddable 도 엔티티와 관계를 맺을 수 있다. 결국 @Embeddable 의 필드들이 @Embedded 가 선언된 곳에 귀속 되므로 @Embeddable 에 @OneToMany 등 엔티티와 관계 설정을 하는 행위 자체가 애초에 @Embedded 에 관계 설정을 한 것과 동일하다.
@AttributeOverride 로 속성을 아래와 같이 재정의도 할 수 있다.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Setter
@Getter
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "HOME_CITY")),
@AttributeOverride(name = "street", column = @Column(name = "HOME_STREET")),
@AttributeOverride(name = "zipcode.zip", column = @Column(name = "HOME_ZIP")),
@AttributeOverride(name = "zipcode.plusFour", column = @Column(name = "HOME_PLUS_FOUR")),
})
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "COMPANY_CITY")),
@AttributeOverride(name = "street", column = @Column(name = "COMPANY_STREET")),
@AttributeOverride(name = "zipcode.zip", column = @Column(name = "COMPANY_ZIP")),
@AttributeOverride(name = "zipcode.plusFour", column = @Column(name = "COMPANY_PLUS_FOUR")),
})
private Address companyAddress;
}
@Embeddable
public class Address {
private String city;
private String street;
@Embedded
private Zipcode zipcode;
}
@Embeddable
public class Zipcode {
private String zip;
private String plusFour;
}
Value Object
앞서 정리한 @Embeddable 도 그렇고 DDD 에서 말하는 애그리거트를 구성하는 엔티티와 밸류 객체 모두 결국 마틴 파울러가 말하는 Value Object 로 구현하는 것이 이상적이다. 책에는 불변 객체의 이점에 대해서 설명되어 있는데, Value Object 가 불변으로 설계가 되어있다.
정리가 잘 된 포스팅들이 여럿 있는데 이 포스팅이 보기가 편한 것 같아서 링크를 남긴다. 필드들을 묶을 수 있는 논리적 단위가 있다면 Value Object 로 만들어서 묶어 주는 것이 더 세밀한 객체 모델링에 가까워지는 것이라고 생각 된다. 생성시 validation 도 각 객체에서 책임을 더 세밀하게 나눠서 처리할 수 있고, 불변 객체로 만들어서 객체를 더 신뢰하고 사용할 수 있다.
JAVA RECORD
자바 14에 프리뷰로 공개되고 16부터 정식 스펙이 된 record 가 Value Object 의 조건들을 만족시킨다. 즉, Value Object 를 손쉽게 만드는 방법으로 자바의 record 를 사용할 수 있다. 관련된 포스팅이 있어 링크를 남긴다.
값 타입 컬렉션(@ElementCollection, @CollectionTable)
@ElementCollection
@CollectionTable(name = "FAVORITE_FOOD", joinColumns = @JoinColumn(name = "MEMBER_ID"))
@Column(name = "FOOD_NAME")
private Set<String> favoriteFoods = new HashSet<>();

값 타입 컬렉션의 제약사항은 각 row 가 pk 를 기준으로 구분되어 인식되는 개체가 아니기 때문에 데이터 하나만 변경이 발생해도 모두 다 지우고 새로 insert 하는 식으로 동작한다는 것이다.
개인적인 경험 내에서는 실무에서 사용하는 경우를 보지는 못했다.
Last updated