
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)
