본문 바로가기
JPA

연관관계 설정

by 혀눅짱 2023. 9. 11.

테이블간의 연관관계 설정에 대해서 간단히 복습해본다. JPA강좌 여러개를 들었고 책도 읽어보았지만 이부분이 제일 낯설고 복잡했던것 같다.

@Entity
@Getter @Setter
@NoArgsConstructor
public class Member extends BaseEntity{

    @Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    @Column(unique = true)
    private String email;

    @Column(length = 200)
    private String pw;

    @NotEmpty
    private String name;

    @Embedded
    private Address address;


    @JsonIgnore
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();

    @Enumerated(EnumType.STRING)
    private MemberRole memberRole;


    @Builder
    public Member(String email, String pw, String name, Address address, List<Order> orders, MemberRole memberRole) {
        this.email = email;
        this.pw = pw;
        this.name = name;
        this.address = address;
        this.orders = orders;
        this.memberRole = memberRole;
    }
}

 

@Entity
@Table(name = "orders")
@Getter @Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED )
public class Order extends BaseUserEntity{

    @Id @GeneratedValue
    @Column(name = "order_id")
    private Long id;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "member_id")
    private Member member;

    @BatchSize(size = 1000)
    @OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> orderItems = new ArrayList<>();

    @OneToOne(fetch = LAZY, cascade = CascadeType.ALL)
    @JoinColumn(name = "delivery_id")
    private Delivery delivery;

    private LocalDateTime orderDate; //시간

    @Enumerated(EnumType.STRING)
    private OrderStatus status; //상태

    //연관관계 메서드
    public void setMember(Member member){
        this.member = member;
        member.getOrders().add(this);
    }

    public void addOrderItem(OrderItem orderItem){
        orderItems.add(orderItem);
        orderItem.setOrder(this);
    }

    public void setDelivery(Delivery delivery){
        this.delivery = delivery;
        delivery.setOrder(this);
    }

    //생성 메서드
    public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems){
        Order order = new Order();
        order.setMember(member);
        order.setDelivery(delivery);
        for(OrderItem orderItem : orderItems){
            order.addOrderItem(orderItem);
        }
        order.setStatus(OrderStatus.ORDER);
        order.setOrderDate(LocalDateTime.now());
        return order;
    }

    //주문취소

    public void cancel(){
        if(delivery.getStatus() == DeliveryStatus.COMP){
            throw new IllegalStateException("이미 배송이 완료된 상품은 취소가 불가능 합니다.");
        }

        this.setStatus(OrderStatus.CANCEL);
        for(OrderItem orderItem : orderItems){
             orderItem.cancel();
        }
    }

    //조회로직
    public int getTotalPrice(){
        int totalPrice = 0;
        for(OrderItem orderItem : orderItems){
            totalPrice += orderItem.getTotalPrice();
        }
        return totalPrice;
    }
}

여기 Member 엔티티와 Order 엔티티가있다. 나는 테이블간에 연관관계를 생각할때 실생활에서 예를들어 접근하는편이다. 이것역시 간단히 생각해보면 내가 온라인 쇼핑몰에 가서 주문을 여러건을 할 수 있다. 이러한 예시를 생각해보면 나(Member)와 주문(Order)간의 관계는 1:N관계가 성립된다. 이 두엔티티를 연관짓기 위해서@OneToMany와 @ManyToOne를 활용한다.

먼저 N쪽에 @ManyToOne을 선언하고 매핑할1의 엔티티 Member를 필드로 선언한다.

그 후

@JoinColumn(name = "member_id")

조인컬럼을 통해 Member엔티티의 어느 필드를 외래키로 쓸것인지를 명시한다. 통상적으론 N측은 1엔티티측의 pk를 외래키로 쓰기때문에 member_id를 외래키로 사용한다.

1측에서는 n측이 선언한 필드명로 매핑한다

@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<>();

하나의 멤버에는 여러개의 주문이있으므로 리스트로 선언한다.

하지만 여기서 member엔티티에서 order에 대한 연관정보를 가지고있을 필요가 없다. 

order의 member_id만 외래키로 가지고있다면

내가 주문한 주문정보를 알고싶다면 member엔티티의 member_id로 조인하여 가져오면되고

주문에있는 멤버들을 알고싶다면 order에 member_id로 조인하면 된다.

 

즉 데이터베이스는 외래키 하나로 양방향 연관관계가 가능하다.

여기서

양방향 매핑의 규칙: 연관관계의 주인
양방향 연관관계 매핑 시 지켜야할 규칙이 있는데 두 연관관계 중 하나를 연관관계의 주인으로 정해야 합니다. 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있습니다. 반면에 주인이 아닌 쪽은 읽기만 할 수 있습니다.
어떤 연관관계를 주인으로 정할지는 mappedBy 속성을 사용하면 됩니다.

주인은 mappedBy 속성을 사용하지 않는다.
주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해야 한다.

쉽게말하면 연관관계의 주인은 외래키를 가지고있는쪽이다 즉 order가 연관관계의 주인이 된다.

연관관계의 주인만 데이터베이스 연관관계와 매핑되고 외래 키를 관리할 수 있습니다. 주인이 아닌 반대편은 읽기만 가능하고 외래 키를 변경하지 못한다.

'JPA' 카테고리의 다른 글

즉시로딩 과 지연로딩 그리고 N+1  (0) 2023.09.20
Entity 상속  (0) 2023.09.13
JPQL  (0) 2023.09.13
영속성 컨텍스트  (0) 2023.09.13
JPA 기본문법 파악  (0) 2023.09.11