JPA/JPA 기본

23. 실전3 다양한 연관관계 매핑

sdafdq 2023. 10. 25. 13:12

여러가지 연관관계를 표현해 보기 위해 만듦.

다대다 쓰지 말라고 했지만 그래도 JPA 공식 스팩이라 해본다고 함.

 

 

ERD(Entity Relationship Diagram)

 

보면 카테고리와 아이템은 사실상 Item이 다 카테고리가 1 관계가 맞는 듯.

 

저걸 토대로 객체 필드를 짜 보면

member
Long id
String name
String city
String street
String zipcode



orders
Long id
Member member
Delivery delivery
LocalDateTime orderDate
OrderStatus status



delivery
Long id
String city
String street
String zipcode
DeliveryStatus status



orderItem
Long id
Order order
Item item
Integer orderPrice
Integer count


item
Long id
String name
Integer price
Integer stockQuantity

이런 느낌 일 듯?

 

예시로 양방향 넣은거 보이고, Member가 orders가지고 있는데 이것도 양방향, 근데 좋아보이진 않음.

 

다대다는 많이 안좋아 보임.

 

그래도 일단 코드

@Entity
public class Member {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name="MEMBER_ID")
    private Long id;
    private String name;
    private String street;
    private String zipcode;
    private String city;

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

일대다이므로 상대(order)에 의해 맵핑되도록.

 

 

@Entity
@Table(name="ORDERS")
public class Order {
    @Id
    @GeneratedValue
    @Column(name="ORDER_ID")
    private Long id;

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @OneToMany(mappedBy = "order")
    private List<OrderItem> orderItems = new ArrayList<>();

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

    @Enumerated(EnumType.STRING)
    private OrderStatus status;

    @OneToOne
    @JoinColumn(name = "DELIVERY_ID")
    private Delivery delivery;
}

member와 다대일로 맵핑. 얘가 주인 외래키도 얘가 가지고 있음.

OrderItem와도 연관관계. 그런데 이때는 얘가 1이고 외래키도 OrderItem이 가지고 있어서 OrderItem의 order에 의해 매핑됨.

 

1:1 연관관계.

얘가 주인 하기로 함.

@JoinColumn해서. 외래키를 얘가 가지고 있기도 하고.

 

@Entity
public class Delivery {
    @Id @GeneratedValue
    private Long id;

    private String city;
    private String street;
    private String zipCOde;

    @Enumerated(EnumType.STRING)
    private DeliveryStatus status;

    @OneToOne(mappedBy = "delivery")
    private Order order;

}

1 : 1 Order의 delivery에 의해 매핑됨.

외래키도 없고, 주인도 아님.

 

@Entity
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 orderPrice;
    private int count;
}

Item과 다대일이므로 얘가 주인.

외래키도 얘가 가지고 있음.

 

Order도 다대일이고, 외래키도 가지고 있어서 

@JoinColumn 해서 주인확정.

 

 

 

@Entity
public class Item {
    @Id
    @GeneratedValue
    @Column(name="ITEM_ID")
    private Long id;
    private String name;
    private int price;
    private int stockQuantity;

    @ManyToMany(mappedBy = "items")
    List<Category> categories = new ArrayList<>();
}

다대다인데, Category에 의해 mapping됨.

 

 

 

@Entity
public class Category {
    @Id @GeneratedValue
    Long id;

    @ManyToOne
    @JoinColumn(name = "PARENT_ID")
    private Category parent;

    @OneToMany(mappedBy = "parent")
    private List<Category> child = new ArrayList<>();

    @ManyToMany
    @JoinTable(name = "CATEGORY_ITEM",
                    joinColumns = @JoinColumn(name="CATEGORY_ID"),
                    inverseJoinColumns = @JoinColumn(name="ITEM_ID")
    )
    private List<Item> items = new ArrayList<>();
}

Category와 다대일?

아니, table 하나 더 만들어서 중개시켜주는 거임. 그래서 다대일 하는 거. 원래는 다대다임.

 

parent에 의해 매핑되는데, 그 parent가 Category 테이블이 가지고 있는 PARENT_ID를 참조해서 가져옴.

 

 

그 후 다대다를 하는데,

다대다는 중개해야 할 테이블이 추가로 필요한가 봄.

그걸 CATEGORY_ITEM이라는 테이블로 정하고,

joinColoumns니 내가 주인이고, 저 테이블에서 CATEGORY_ID를 참조.

inverseJoinColumns는 반대쪽이 참고해야 할 열임. 반대쪽에서 참고하는 건 CATEGORY_ITEM 테이블의 ITEM_ID 열임.

 

Category에서 item을 찾을 때 저렇게 찾는 거임.

 

 

다대다는 N : M은

중간테이블을 사용해 중개해주도록 하라.

지금도 사실 단순한 편이고 실전은 중간테이블은 단순하지 않음.

 

다대다는 실전에서 쓰지 말길.

 

 

name이 매핑할 내 테이블의 외래키 이름.

가끔 외래키가 참조하는 대상 테이블의 컬럼명이 달라지는 경우가 있는데,

referencedColumnName 써 주면 된다.

대상 테이블에 있는 열의 이름.

기본값은 참조하는 테이블의 기본키(primary key)

 

 

다대일 할 때 쓰는 것 들.

optional은 설명 그대로 연관된 @Entity가 꼭 있어야 한다는 거고,

fetch, cascade 등은 나중에 설명한다고 한다.

targetEntity는 엔티티의 타입 정보를 지정해주는 그런건가?

근데 이거는 이제 거의 사용되지 않음.

제네릭도 있고 알아서 잘 가져옴.

 

 

보면 일대다는 mappedBy가 있다.

아까 다대일은 없었다.

즉, 공식이 다대일을 주인으로 하라는 말이다.

물론 단방향에 일대다면 쟤가 주인이 될 수 있지만.

 

 

'JPA > JPA 기본' 카테고리의 다른 글

25. Mapped Superclass 매핑 정보 상속  (0) 2023.10.27
24. 상속관계 매핑  (0) 2023.10.26
22. N : M 다대다 연관관계  (0) 2023.10.25
21. 1 : 1 연관관계  (0) 2023.10.25
20. 1:N 일대다  (0) 2023.10.24