05 상품 도메인 개발 - Item Entity, Repository, Service

shin·2023년 9월 17일
0
post-thumbnail

[구현 기능]

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

1. Item Entity + 비즈니스 로직 추가

1) Item Entity 구현

package jpabook.jpashop.domain;

import jakarta.persistence.*;
import jpabook.jpashop.exception.NotEnoughStockException;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@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> items = new ArrayList<>();

    // 비즈니스 로직
    /**
     * 재고 증가
     */
    public void addStock(int quantity){
        this.stockQuantity += quantity;
    }

    /**
     * 재고 감소
     */
    public void removeStock(int quantity){
        int restStock = this.stockQuantity - quantity;
        if(restStock < 0){
            throw new NotEnoughStockException("need more stock");
        }
        this.stockQuantity = restStock;
    }
}
package jpabook.jpashop.exception;

public class NotEnoughStockException extends RuntimeException {

    public NotEnoughStockException() {
        super();
    }

    public NotEnoughStockException(String message) {
        super(message);
    }

    public NotEnoughStockException(String message, Throwable cause) {
        super(message, cause);
    }

    public NotEnoughStockException(Throwable cause) {
        super(cause);
    }
}

2) 코드 상세 설명

객체 지향적인 개발 방식

  • 데이터를 가지고 있는 쪽에 비즈니스 메서드를 있는 것이 좋음
  • 따라서 핵심 비즈니스 로직을 엔티티에 직접 넣음
  • 엔티티의 값을 변경할 때 Setter를 사용하지 않고, 핵심 비즈니스 로직을 구현한 메서드를 사용해서 값을 변경해야 함

비즈니스 로직 분석

  • addStock()
    • 파라미터로 넘어온 수만큼 재고를 늘림
    • 재고가 증가하거나 상품 주문을 취소해서 재고를 다시 늘려야 할 때 사용
  • removeStock()
    • 파라미터로 넘어온 수만큼 재고를 줄임
    • 만약 재고가 부족하면 예외가 발생함
    • 주로 상품 주문시 사용


2. Item Repository

1) Item Repository 구현

package jpabook.jpashop.repository;

import jakarta.persistence.EntityManager;
import jpabook.jpashop.domain.Item;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
@RequiredArgsConstructor
public class ItemRepository {

    private final EntityManager em;

    public void save(Item item){
        if(item.getId() == null) {
            em.persist(item);
        } else {
            em.merge(item);
        }
    }

    public Item findOne(Long id){
        return em.find(Item.class, id);
    }

    public List<Item> findAll() {
        return em.createQuery("select i from Item i", Item.class)
                .getResultList();
    }
}

2) 코드 상세 설명

save() - persist or merge

  • 저장하고자 하는 item의 id 값 존재 여부 확인

  • id 값이 없으면 신규로 보고 persist() 실행

  • id 값이 있으면 수정으로 보고 merge() 실행

    • 이미 데이터베이스에 저장된 엔티티 수정
  • persist()

    • 리턴값이 없는 insert
    • 파라미터로 받은 entity를 영속성으로 바꾸어 반환
  • merge()

    • 리턴값이 없는 update
    • 식별자 값으로 엔티티를 조회할 수 있으면 불러서 병합하고 조회할 수 없으면 새로 생성해서 병합함
    • 한 번 persist 상태였다가 detached된 상태에서, 그 다음에 Managed 상태가 될 때 merge한다고 함

엔티티 생명주기 정리
https://velog.io/@syb0228/Entity-LifeCycle



3) Item Service

1) Item Service 구현

package jpabook.jpashop.service;

import jpabook.jpashop.domain.Item;
import jpabook.jpashop.repository.ItemRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ItemService {

    private final ItemRepository itemRepository;

    /**
     * 상품 등록
     * @param item
     * @return Long
     */
    @Transactional
    public Long saveItem(Item item){
        itemRepository.save(item);
        return item.getId();
    }

    /**
     * 상품 단건 조회
     * @param id
     * @return Item
     */
    public Item findOne(Long id){
        return itemRepository.findOne(id);
    }

    /**
     * 상품 전체 조회
     * @return List<Item>
     */
    public List<Item> findItems(){
        return itemRepository.findAll();
    }
}
  • 상품 서비스는 상품 리포지토리에 단순히 위임만 하는 클래스


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

profile
Backend development

0개의 댓글