코드 그라데이션

실전 예제 1 - 요구사항 분석과 기본 매핑 본문

Spring/JPA 공부

실전 예제 1 - 요구사항 분석과 기본 매핑

완벽한 장면 2023. 8. 17. 03:49

이것 아마 인프런 <실전 스프링 부트와 JPA 활용 1편> 예제와 동일하거나 최소한 비슷한 듯.

 

요구사항 분석

  • 회원은 상품을 주문할 수 있다.
  • 주문 시 여러 종류의 상품을 선택할 수 있다.

 

기능 목록

회원 기능

  • 회원 등록
  • 회원 조회

상품 기능

  • 상품 등록
  • 상품 조회
  • 상품 수정

주문 기능

  • 상품 주문
  • 주문 내역 조회
  • 주문 취소

 

완성된 페이지 모양

 

도메인 모델 분석

회원과 주문의 관계

  • 회원은 여러 번 주문할 수 있다.(일대다)

주문과 상품의 관계

  • 주문할 때 여러 상품을 선택할 수 있다.
  • 같은 상품도 여러 번 주문될 수 있다.
  • '주문상품'이라는 모델을 만들어서 다대다 관계를 일대다, 다대일 관계로 풀어낸다.

 

 

테이블 설계

기본 테이블 설계도

 

엔티티 설계와 매핑

엔티티 설계와 매핑

 


이제, 기초 코드

Item

@Entity
public class Item {

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

  private String name;
  private int price;
  private int stockQuantity;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public int getPrice() {
    return price;
  }

  public void setPrice(int price) {
    this.price = price;
  }

  public int getStockQuantity() {
    return stockQuantity;
  }

  public void setStockQuantity(int stockQuantity) {
    this.stockQuantity = stockQuantity;
  }
}

 

 

Member

@Entity
public class Member {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "MEMBER_ID")
  private Long id;

  private String name;
  private String city;
  private String street;
  private String zipcode;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getCity() {
    return city;
  }

  public void setCity(String city) {
    this.city = city;
  }

  public String getStreet() {
    return street;
  }

  public void setStreet(String street) {
    this.street = street;
  }

  public String getZipcode() {
    return zipcode;
  }

  public void setZipcode(String zipcode) {
    this.zipcode = zipcode;
  }
}

 

 

Order

@Entity
@Table(name = "orders")
public class Order {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "ORDER_ID")
  private Long id;

  @Column(name = "MEMBER_ID")
  private Long memberId;

//  private Member member;

  private LocalDateTime orderDate;

  @Enumerated(EnumType.STRING)
  private OrderStatus status;


  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public Long getMemberId() {
    return memberId;
  }

  public void setMemberId(Long memberId) {
    this.memberId = memberId;
  }

  public LocalDateTime getOrderDate() {
    return orderDate;
  }

  public void setOrderDate(LocalDateTime orderDate) {
    this.orderDate = orderDate;
  }

  public OrderStatus getStatus() {
    return status;
  }

  public void setStatus(OrderStatus status) {
    this.status = status;
  }

//  public Member getMember() {
//    return member;
//  }
//
//  public void setMember(Member member) {
//    this.member = member;
//  }
}

 

 

OrderItem

@Entity
public class OrderItem {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  @Column(name = "ORDER_ITEM_ID")
  private Long id;

  @Column(name = "ORDER_ID")
  private Long orderId;

  @Column(name = "ITEM_ID")
  private Long itemId;

  private int orderPrice;

  private int count;

  public Long getId() {
    return id;
  }

  public void setId(Long id) {
    this.id = id;
  }

  public Long getOrderId() {
    return orderId;
  }

  public void setOrderId(Long orderId) {
    this.orderId = orderId;
  }

  public Long getItemId() {
    return itemId;
  }

  public void setItemId(Long itemId) {
    this.itemId = itemId;
  }

  public int getOrderPrice() {
    return orderPrice;
  }

  public void setOrderPrice(int orderPrice) {
    this.orderPrice = orderPrice;
  }

  public int getCount() {
    return count;
  }

  public void setCount(int count) {
    this.count = count;
  }
}

 

 

OrderStatus

public enum OrderStatus {
  ORDER, CANCEL
}

 

JpaShopMain

public class JpaShopMain {
  public static void main(String[] args) {
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
    EntityManager em = emf.createEntityManager();

    EntityTransaction tx = em.getTransaction();
    tx.begin();

    try {
//     Order order = em.find(Order.class, 1L);
//     Long memberId = order.getMemberId();

//      Member member = em.find(Member.class, memberId);
//      Member findMember1 = order.getMember();

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
    } finally {
      em.close();
    }
    emf.close();
  }
}

 

 

이걸 실행해보면

따로 정해주지 않으면 컬럼명과 필드명이 동일하게 간다고 생각하면 된다.

Hibernate: 
    
    create table Item (
       ITEM_ID bigint not null,
        name varchar(255),
        price integer not null,
        stockQuantity integer not null,
        primary key (ITEM_ID)
    )
01:54:32.744 [main] DEBUG org.hibernate.SQL - 

Hibernate: 
    
    create table Member (
       MEMBER_ID bigint not null,
        city varchar(255),
        name varchar(255),
        street varchar(255),
        zipcode varchar(255),
        primary key (MEMBER_ID)
    )
01:54:32.745 [main] DEBUG org.hibernate.SQL - 

Hibernate: 
    
    create table OrderItem (
       ORDER_ITEM_ID bigint not null,
        count integer not null,
        ITEM_ID bigint,
        ORDER_ID bigint,
        orderPrice integer not null,
        primary key (ORDER_ITEM_ID)
    )
01:54:32.746 [main] DEBUG org.hibernate.SQL - 

Hibernate: 
    
    create table orders (
       ORDER_ID bigint not null,
        MEMBER_ID bigint,
        orderDate timestamp,
        status varchar(255),
        primary key (ORDER_ID)
    )

메타데이터는 그냥 엔티티 클래스에 그대로 적어라.

이 엔티티만 봐도 개발자가 바로 알 주 있으니까.

인덱스도 웬만하면 적어라.

그래야 개발자들이 JPQL 같은 걸 짤 때 테이블 보고 왓다갔다 하는 등의 번거로움을 줄일 수 있게 됨.

 


Order를 한 멤버를

사실      

@Column(name = "MEMBER_ID")
  private Long memberId;

이렇게 찾을 게 아니라.

(이렇게 찾아버리면 

try {
      Order order = em.find(Order.class, 1L);
      Long memberId = order.getMemberId();

      Member member = em.find(Member.class, memberId);

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
    } finally {
      em.close();
    }

이렇게 매우 성가신 코드가 되므로 객체지향적이라고 보기엔 좀 그렇다...

 

그래서 

private Member member;

이렇게 엔티티를 바로 필드로 받아서

    try {
      Order order = em.find(Order.class, 1L);
//      Long memberId = order.getMemberId();
//
//      Member member = em.find(Member.class, memberId);
      Member findMember1 = order.getMember();

      tx.commit();
    } catch (Exception e) {
      tx.rollback();
    } finally {
      em.close();
    }
    emf.close();
  }

이렇게 바로 받을 수 있다.

728x90
Comments