02 도메인 분석 설계 - 엔티티 클래스 개발

shin·2023년 7월 31일
0

1. 엔티티 클래스 개발

🚨 @Setter 사용을 지양해야 하는 이유

  • 이론적으로 Getter, Setter를 모두 제공하지 않고 꼭 필요한 별도의 메서드를 제공하는 것이 가장 이상적이지만, 실무에서는 엔티티의 데이터는 조회할 일이 많기 때문에 Getter의 경우 모두 열어두는 것이 편리함
  • Getter는 애초에 조회만 수행하는 것이 때문에 사용한다고 해서 큰 문제가 발생하지는 않음
  • 하지만, Setter의 경우 호출하면 데이터가 변하기 때문에, Setter를 열어두면 가까운 미래에 엔티티가 어떻게 변경될 것인지 추적하기가 힘들어짐
  • 따라서 엔티티를 변경할 때는 변경 지점이 명확하도록 비즈니스 메서드를 별도로 제공해야 함

Member Entity

@Entity
@Getter
public class Member {

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

   private String name;

   @Embedded
   private Address address;

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

주문 Entity

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

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

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

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

    @OneToOne(fetch = FetchType.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);
    }

}

OrderStatus Enum

public enum OrderStatus {
 	ORDER, CANCEL 
}

OrderItem Entity

@Entity
@Table(name = "order_item")
@Getter @Setter
public class OrderItem {

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

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "item_id")
    private Item item;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "order_id")
    private Order order;

    private int orderPrice; //주문가격
    private int count; //주문수량
   
}

Item Entity

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")
@Getter
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<Category>();
 
}

Item - Book Entity

@Entity
@DiscriminatorValue("B")
@Getter
public class Book extends Item {

   private String author;
   private String isbn;
   
}

Item - Album Entity

@Entity
@DiscriminatorValue("A")
@Getter
public class Album extends Item {

   private String artist;
   private String etc;
   
}

Item - Movie Entity

@Entity
@DiscriminatorValue("M")
@Getter
public class Movie extends Item {

   private String director;
   private String actor;
   
}

Delivery Entity

@Entity
@Getter @Setter
public class Delivery {

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

    @OneToOne(mappedBy = "delivery", fetch = FetchType.LAZY)
    private Order order;

    @Embedded
    private Address address;

    @Enumerated(EnumType.STRING)
    private DeliveryStatus status;
   
}

DeliveryStatus Enum

public enum DeliveryStatus {

	READY, COMP
 
}

Category Entity

@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<>();

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private Category parent;

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

    // 연관관계 메서드
    public void addChildCategory(Category child){
        this.child.add(child);
        child.setParent(this);
    }

}

Address Entity

@Embeddable
@Getter
public class Address {

   private String city;
   private String street;
   private String zipcode;
   
   protected Address() {
   }
   
   public Address(String city, String street, String zipcode) {
      this.city = city;
      this.street = street;
      this.zipcode = zipcode;
   }
   
}
  • 값 타입은 변경 불가능하게 설계해야 함
    • @Setter를 제거하고 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들어야 함
    • JPA 스펙상 엔티티나 인베디드 타입은 자바 기본 생성자를 public 또는 protected로 설정해야 함

설계한 그대로 테이블 생성 완료


강의 : 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

profile
Backend development

0개의 댓글