-
회원 도메인 개발JPA/JPA 활용 2023. 7. 11. 18:07
사진출처 : 김영한님 인프런 강의 위의 사진과 같이 상품을 주문하는 도메인을 개발할 것이다.
사진출처 : 김영한님 인프런 강의 각각의 Entity들을 살펴보면 관계형 데이터베이스의 의존관계를 통해 필요한 관계형 db들끼리 연관이 되어있다.
사진출처 : 김영한님 인프런 강의 코드로 작성을 하기 전에 어떤 변수들이 필요한지, FK(foreign key)는 어떤 db의 변수로 지정할 지 등을 먼저 정리하고 코드로 작성하는 것이 좋다.
관계형 데이터 베이스는 3가지 형태가 있다.
- ManyToOne : 여러개와 하나의 관계를 나타냄 order에서 member와의 관계
- OneToMany : 하나와 여러개의 관계를 나타냄 member에서 order의 관계
- ManyToMany : 여러개 사이의 관계를 나타냄(사용 되도록 하지 않기)
일대 다 관계에서는 FK를 다수쪽에 넣기(Member와 Order가 있으면 Order에 FK)
일대 일 관계에서는 FK를 access 많이 하는 곳에 넣기다대 다 관계는 실무에서 사용하면 안됨
Order.class
@Entity @Table(name = "orders") // 이거 하지 않으면 관례로 order로 들어감 @Getter @Setter public class Order { @Id @GeneratedValue @Column(name = "order_id") private Long id; @ManyToOne @JoinColumn(name = "member_id") // FK(foreign key) private Member member; @OneToMany(mappedBy = "order") //order에 의해서 mapping이 되었다는 뜻 private List<OrderItem> orderItems = new ArrayList<>(); @OneToOne @JoinColumn(name = "delivery_id") private Delivery delivery; private LocalDateTime orderDate; // 주문 시간, 자바에서 기본으로 지원해주는 시간기능 @Enumerated(EnumType.STRING) // Enum을 string으로 받아온다는 애노테이션 private OrderStatus status; // 주문 상태 [ORDER, CANCEL] (enum 타입) }
엔티티를 설계할 때 FK와 의존관계들을 잘 고려해야한다. order 엔티티는 member_id와 delivery_id 대해 FK를 갖는다. FK가 된다는 뜻인 @JoinColumn을 통해 관계를 맺을 value에 접근하는 것이고, FK가 아닌 값은 @JoinColumn 애노테이션을 안 붙이면 된다. OrderItem의 관계에서는 OrderItem이 FK를 갖기 때문에 @joinColum 애노테이션이 없다.
Member.class
@Entity @Getter @Setter public class Member { @Id @GeneratedValue @Column(name = "member_id") private Long id; private String name; @Embedded // Address 클래스의 @Embeddable과 이것중 하나만 적어도 되긴하는데 둘 다 적는 편 private Address address; @OneToMany(mappedBy = "member") // order table에 있는 member 필드에 의해 매핑되었다는 뜻 // 연관관계의 주인은 FK가 가까운 곳으로 하면 됨 -> order에 있는 foreign key가 주인이다. private List<Order> orders = new ArrayList<>(); }
Member 엔티티는 order 리스트와 관계가 있다. member 하나에 order 여러개가 있을 수 있으므로 @OneToMany 애노테이션을 사용했다. 또한 @Embedded로 Address를 받아왔는데 Member 엔티티에서 사용하는 내장타입의 클래스이다.
Address.class
@Embeddable // JPA의 내장타입이기 때문에 @Embeddable @Getter public class Address { private String city; private String street; private String zipcode; }
Delivery.class
@Entity @Getter @Setter public class Delivery { @Id @GeneratedValue @Column(name = "delivery_id") private Long id; @OneToOne(mappedBy = "delivery") private Order order; @Embedded private Address address; @Enumerated(EnumType.STRING) // EnumType은 무조건 String으로 받기 private DeliveryStatus status; // READY, COMP }
delivery 엔티티는 order 엔티티와 @OneToOne 관계를 가진다. 또한 위에서 사용했던 Address를 재사용했다.
@Enumerated는 DeliveryStatus라는 enum의 상태를 받아온다는 뜻이다.
DeliveryStatus.enum
public enum DeliveryStatus { READY, COMP }
OrderItem.class
@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") // order에 있는 id를 매핑 private Order order; private int orderPrice; // 주문 "당시"의 가격 private int count; // 주문 당시의 수량 }
orderitem 엔티티는 item, order과 관계형 db 관계인데, order_id와 item_id 모두에서 FK인 존재이다.
이렇게 access가 많은 엔티티가 FK를 가지는게 일반적이다.
Item.class
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "dtype") @Getter @Setter public abstract class Item { @Id @GeneratedValue @Column(name = "item_id") private Long id; private String name; private int price; private int stockQuantity; @ManyToMany(mappedBy = "items") private List<Category> categories = new ArrayList<>(); }
Item은 abstract class로 선언되어서 @Inheritance를 하게 된다.
@DiscriminatorColumn(name = 'dtype')은 item들을 분류하는 에노테이션이다. 예를 들어 Book.class를 보면
@Entity @DiscriminatorValue("B") @Getter @Setter public class Book extends Item{ private String author; private String isbn; }
@DiscriminatorValue("B")로 Book을 B로 분류한 것이다.
Category.class
@Entity @Getter @Setter public class Category { @Id @GeneratedValue @Column(name = "category_id") private Long id; private String name; @ManyToMany @JoinTable(name = "category_item", joinColumns = @JoinColumn(name = "category_id"), inverseJoinColumns = @JoinColumn(name = "item_id") ) private List<Item> items = new ArrayList<>(); // ~35까지 @ManyToOne @JoinColumn(name = "parent_id") private Category parent; @OneToMany(mappedBy = "parent") private List<Category> child = new ArrayList<>(); // 상속관계의 연관관계 (카테고리도 상속이 있을 수 있으니까 (음식에 우유, 빵이 있듯이)) }
카테고리에서 ManyToMany를 사용했는데 @JoinTable이라는 중간 테이블 매핑을 통해 category_item이라는 테이블을 생성해서 다대 다를 일대 다, 다대 일로 분리해주는 @JoinTable이 필요하다. 하지만 필드를 추가한다거나 그런 기능은 안되고 단순히 서로 관계 매핑만 되기 때문에 실무에서는 사용하지 않는다고 한다.
아래 두 변수들은 상속관계의 연관관계이다. 카테고리에도 상속이 있을 수 있으므로 같은 엔티티에서도 관계 매핑을 해준 것이다.
'JPA > JPA 활용' 카테고리의 다른 글
상품 리포지토리, 서비스 개발 (0) 2023.07.11 상품 엔티티 개발(비즈니스 로직) (0) 2023.07.11 회원 가입, 조회 기능 테스트 (0) 2023.07.11 회원 리포지토리, 서비스 개발 (0) 2023.07.11 엔티티 설계시 주의점 (0) 2023.07.11