RDBMS 사용 시 객체 기반의 도메인 모델과 관계형 데이터 모델 간 매핑을 처리하는 기술로 ORM만한 것이 없다.
애그리거트 루트는 @Entity
로 매핑 설정한다.
@Entity
@Table(name = "purchase_order")
public class Order { ... }
밸류는 @Embeddable
로 매핑 설정한다.
@Embeddable
public class Orderer {
@Embedded
@AttributeOverridesss(
@AttributeOverride(name = "id", @Column(name = "orderer_id"))
)
private MemberId memberId
MemberId
에 정의된 칼럼 이름을 변경하기 위해 @AttributeOvveride
애너테이션을 사용했다. @Embeddable
public class MemberId implements Serializable {
@Column(name = "member_id")
private String id;
}
밸류 타입 프로퍼티는 @Embedded
로 매핑 설정한다.
@Embedded
private Orderer orderer;
밸류 타입의 여러 프로퍼티를 한 개 칼럼에 매핑하거나 다른 형식으로 DB 칼럼에 적용해야할 때가 있다.
public class Length {
private int value;
private String unit;
// ...
}
// -> DB에 'WIDTH VARCHAR(20)'으로 저장하려면?
AttributeConverter
를 사용하면 밸류 타입과 칼럼 데이터 간 변환을 처리할 수 있다.
public interface AttributeConverter<X, Y> {
Y convertToDatabaseColumn(X attribute);
X convertToEntityAttribute(Y dbData);
}
@Embedded
@Converter(converter = LengthConverter.class)
private Length length
@Converter
의 autoApply
속성은 기본적으로 false
인데 이는 컨버터를 직접 지정해야 한다는 것이다.식별자라는 의미를 부각시키기 위해 식별자 자체를 밸류 타입으로 만들 수도 있다.
@Entity
@Table(name = "purchase_order")
public class Order {
@EmbeddedId
private OrderNo number;
}
식별자 타입은 Serializable
타입이어야 한다.
@Embeddable
public class OrderNo implements Serializable {
@Column(name="order_number")
private String number;
}
equals()
와 hashcode()
를 알맞게 구현해야 한다.밸류 타입을 별도의 테이블로 사용하려면 @SecondaryTable
과 @AttributeOvveride
를 사용한다.
@Entity
@SecondaryTable(
name = "article_content",
pkJoinColumns = @PrimaryKeyJoinColumn(name = "id")
)
public class Article {
// ...
@AttributeOverrides({
@AttributeOverride(
name = "content",
column = @Column(table=="article_content", name="content")),
@AttributeOvveride(
name = "contentType",
column = @Column(table="article_content", name="content_type"))
})
@Embedded
private ArticleContent content;
// ...
}
@SecondaryTable
의 name
속성은 밸류를 저장할 테이블을 지정한다.pkJoinColumns
속성은 밸류 테이블에서 엔티티 테이블로 조인할 때 사용할 칼럼을 지정한다.@Entity
를 사용해야 할 때도 있다.
@Embeddable
타입 클래스는 상속 매핑을 지원하지 않기에 엔티티로 만들 수밖에 없다.@Entity
public class Product {
@EmbeddedId
private ProductId id;
@ElementCollection
@CollectionTable(
name = "Product_category",
joinColumns = @JoinColumn(name="product_id")
)
private Set<CategoryId> categoryIds;
// ...
}
@ElementCollection
을 이용하기에 Product
를 삭제할 때 매핑에 사용한 조인 테이블의 데이터도 함께 삭제된다.cascade
속성과 orphanRemoval
속성을 사용하여 구현할 수 있다.
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE},
orphanRemoval = true)
@JoinColumn(name = "product_id")
private List<Image> images = new ArrayList<>();
public class CreateProductService {
private ProductIdService idService;
private ProductRepository productRepositoroy;
@Transactional
public ProductId createProduct(ProductCreationReq req) {
ProductId id = idService.nextId();
Product product = new Product(id, req.getDetail());
productRepository.save(product);
return id;
}
}
@GeneratedValue
를 사용하면 된다.JpaRepository
를 상속하고 있다.