public interface OrderRepository {
Optional<Order> findById(OrderNo id);
void save(Order order);
}
@Entity
로 매핑한다.@Embeddable
로 매핑한다.@Embedded
로 매핑한다.import com.myshop.order.command.domain.Receiver;
import com.myshop.order.command.domain.ShippingInfo;
import javax.persistence.Embedded;
@Entity
@Table(name = "ORDERS")
public class Order {
// ...
@Embedded
private Orderer orderer;
@Embedded
private ShippingInfo shippingInfo;
}
@Embeddable
public class Orderer {
@Embedded
@AttributeOverrides(
@AttributeOverride(name = "id", column = @Column(name = "ORDERER_ID"))
)
private MemberId memberId;
@Column(name = "ORDERER_NAME")
private String name;
}
@Embeddable
public class MemberId implements Serializable {
@Column(name = "MEMBER_ID")
private String id;
}
@Embeddable
public class ShippingInfo {
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "zipCode", column = @Column(name = "SHIPPING_ZIP_CODE")),
@AttributeOverride(name = "address1", column = @Column(name = "SHIPPING_ADDRESS1")),
@AttributeOverride(name = "address2", column = @Column(name = "SHIPPING_ADDRESS2"))
})
private Address address;
@Column(name = "SHIPPING_MESSAGE")
private String message;
@Embedded
private Receiver receiver;
}
@Entity
와 @Embeddable
로 Class를 매핑하려면, 기본 생성자가 있어야 한다.protected
혹은 패키지 범위로 기본 생성자를 선언하는 것을 추천한다.import javax.persistence.Column;
@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Receiver {
@Column(name = "RECEIVER_NAME")
private String name;
@Column(name = "RECEIVER_PHONE")
private String phone;
public Receiver(String name, String phone) {
this.name = name;
this.phone = phone;
}
}
@Convert
, @Converter
를 이용해서 Value 타입을 매핑한다.@Converter(autoApply = true)
를 이용하면, 모든 Entity에 대해 자동으로 매핑한다.public interface AttributeConverter<X, Y> {
Y convertToDatabaseColumn(X var1);
X convertToEntityAttribute(Y var1);
}
@ElementCollection
과 @CollectionTable
을 이용한다.import javax.persistence.CollectionTable;
import javax.persistence.ElementCollection;
import javax.persistence.OrderColumn;
@Entity
@Table(name = "ORDERS")
public class Order {
@EmbeddedId
private OrderNo number;
@ElementCollection
@CollectionTable(name = "ORDER_LINES", joinColumns = @JoinColumn(name = "ORDER_NUMBER"))
@OrderColumn(name = "LINE_IDX")
private List<OrderLine> orderLines;
// ...
}
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
@Embeddable
public class OrderLine {
@Embedded
private ProductId productId;
@Column(name = "PRICE")
private Money price;
@Column(name = "QUANTITY")
private int quantity;
@Column(name = "AMOUNTS")
private Money amounts;
// ...
}
public @interface ElementCollection {
Class targetClass() default void.class;
FetchType fetch() default FetchType.LAZY;
}
public @interface CollectionTable {
String name() default "";
String catalog() default "";
String schema() default "";
JoinColumn[] joinColumns() default {};
ForeignKey foreignKey() default @ForeignKey(ConstraintMode.PROVIDER_DEFAULT);
UniqueConstraint[] uniqueConstraints() default {};
Index[] indexes() default {};
}
@EmbeddedId
와 @Embeddable
을 이용해서 식별자를 Value 타입으로 매핑한다.Serializable
을 구현해야 한다.equals()
와 hashCode()
를 구현해야 한다.import javax.persistence.Table;
@Entity
@Table(name = "ORDERS")
public class Order {
@EmbeddedId
private OrderNo number;
// ...
}
@Embeddable
public class OrderNo implements Serializable {
@Column(name = "ORDER_NUMBER")
private String number;
private boolean is2ndGeneration() {
return number.startsWith("N");
}
}
@Entity
로 매핑할 수 있다. @Inheritance
@DiscriminatorColumn
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)
@Embeddable
을 통해서 매핑한다면, 단순히 delete 쿼리만 실행한다.import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.EmbeddedId;
import javax.persistence.Table;
@Entity
@Table(name = "PRODUCT")
public class Product {
@EmbeddedId
private ProductId id;
@ElementCollection
@CollectionTable(
name = "PRODUCT_CATEGORY",
joinColumns = @JoinColumn(name = "PRODUCT_ID")
)
private Set<CategoryId> cartegoryIds;
}
애그리거트에 맞게 즉시 로딩과 지연 로딩을 적절하게 선택해야한다.
저장 메서드는 애그리거트 루트만 저장하면 안되고, 애그리거트에 속한 모든 객체를 저장해야 한다.
삭제 메서드는 애그리거트 루트뿐만 아니라 애그리거트에 속한 모든 객체를 삭제해야 한다.
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, orphanRemoval = true)