이전 포스팅들에서는 단방향 매핑하는 방법에 대해서만 알아보았었다.
이번 포스팅에서는 단방향이 아닌 양방향 매핑하는 방법에 대해 알아보고자 한다.
먼저 양방향 매핑이란 간단하게 단방향 매핑이 2개 있다고 생각하면 쉽다.
이전 포스팅에 의하면 현재 장바구니 상품(CartItem) 엔티티가 장바구니(Cart)를 참조하고 있는 단방향 매핑이다.
장바구니 엔티티에 장바구니 상품 엔티티를 일대다 관계로 매핑을 해주면 양방향 매핑이 된다.
정말 간단하다.
이번에는 주문(Order)과 주문 상품(OrderItem)의 매핑을 통해 양방향 매핑에 대해 더 깊게 알아보고자 한다.
먼저 주문 엔티티를 설계하기 전에 주문의 상태를 나타내는 OrderStatus enum을 만들겠다.
public enum OrderStatus {
ORDER,CANCEL
}
주문한 상태인 ORDER와 주문을 취소한 상태인 CANCEL가 있다.
주문 엔티티에는 주문 번호를 나타내는 ID와 주문 하는 주체인 Member의 ID, 주문일, 주문 상태, 등록, 업데이트 시간이 포함되어야 한다.
이를 토대로 엔티티를 설계하면 아래와 같다.
@Entity
@Getter @Setter
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "order_id")
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
private LocalDateTime orderDate; //주문일
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus;
private LocalDateTime regTime;
private LocalDateTime updateTime;
}
테이블의 이름은 순서를 정렬할 때 사용하는 ‘order’ 키워드가 있기 때문에 오류가 발생하지 않도록 ‘orders’로 지정해주었다.
또한 한 명의 회원은 여러 번의 주문을 할 수 있기 때문에 주문 엔티티를 기준으로 했을 때 @ManyToOne 어노테이션을 사용해 다대일 단방향 매핑을 해주었다.
주문 상품 엔티티는 장바구니 상품 엔티티와 거의 비슷하다.
주문 상품 엔티티와 주문 엔티티의 단방향 매핑을 먼저 설정하겠다.
@Entity
@Getter @Setter
public class OrderItem {
@Id
@GeneratedValue
@Column(name = "order_item_id")
private Long id;
@ManyToOne
@JoinColumn(name="item_id")
private Item item;
@ManyToOne
@JoinColumn(name = "order_id")
private Order order;
private int oderPrice;
private int count;
private LocalDateTime regTime;
private LocalDateTime updateTime;
}
하나의 상품(Item)은 여러 주문 상품(OrderItem)으로 들어갈 수 있으므로 주문 상품 기준으로 다대일 관계 매핑 설정을 해주었다.
한 번의 주문(Orders) 여러개의 주문 상품(OrderItem)을 주문할 수 있으므로 주문 상품 엔티티와 주문 엔티티를 다대일 관계 매핑 설정을 해주었다.
다대일과 일대다는 반대 관계라고 생각하면 된다.
주문 상품 엔티티 기준에서 다대일 매핑이엇으므로 주문 엔티티 기준에서는 주문 사움 엔티티와 일대다 관계로 매핑하면 된다.
또한 양방향 매핑에서는 ‘연관 관계 주인'을 설정해야 한다는 점이 중요하다.
주문(Orders)와 주문 상품(OrderItem)테이블을 order_id를 외래키로 조인하면 주문에 속한 상품이 어떤 상품들이 있는지 알 수 있고, 주문 상품은 어떤 어떤 주문에 속하는지 알 수 있다.
즉, 테이블은 외래키 하나로 양방향 조회가 가능하다는 말이다.
하지만 엔티티는 테이블과 다르다.
엔티리를 양방향 연관 관계로 설정하면 객체의 참조는 둘인데 외래키는 하나이므로 둘 중 누가 외래키를 관리할 지를 정해야 한다.
아래 코드를 통해 위의 내용을 적용해보겠다.
연관 관계의 주인 설정을 자세히 봐야 한다.
Order 엔티티에 OrderItem과 연관 관계 매핑을 추가해보겠다.
OrderItem 엔티티에서 이미 다대일 단방향 매핑을 했으므로 양방향 매핑이 된다.
@Entity
@Getter @Setter
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "order_id")
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
private LocalDateTime orderDate; //주문일
@Enumerated(EnumType.STRING)
private OrderStatus orderStatus;
private LocalDateTime regTime;
private LocalDateTime updateTime;
@OneToMany(mappedBy = "order")
private List<OrderItem> orderItems = new ArrayList<>();
}
기존 Order 엔티티에서 마지막 두줄만 추가된 소스코드이다.
OrderItem 엔티티에서 다대일 관계로 매핑을 해주었기 때문에 반대로 일대다 관계로 매핑을 해주었다.
또한 OrderItem 엔티티가 외래키인 order_id를 가지고 있기 때문에 연관 관계의 주인이다.
그렇기 때문에 mappedBy 속성을 통해 OrderItem의 외래키인 Order의 필드값인 order를 적어주었다.
마지막으로 하나의 주문이 여러 개의 주문 상품을 갖으므로 List 자료형을 사용해 매핑을 해주었다.
무조건 양방향으로 연관 관계를 매핑하면 해당 엔티티는 엄청나게 많은 테이블과 연관 관계를 맺게 된다.
이렇게 되면 엔티티 클래스 자체가 복잡해지기 때문에 연관 관계 단방향 매핑으로 설계 후 나중에 필요할 경우에만 양방향 매핑을 할 것을 추천한다.