[Error] [스프링 스터디] 쇼핑몰 만들기 프로젝트 - JPA 연관관계 재설정

myeonji·2022년 1월 30일
0

java.sql.SQLException: Cannot delete or update a parent row: a foreign key constraint fails (shopstudy.order_item, CONSTRAINT FKija6hjjiit8dprnmvtvgdp6ru FOREIGN KEY (item_id) REFERENCES item (id))

상품 CRUD, 장바구니, 주문, 주문취소 기능까지 마치고.. 전체 기능 테스트를 하다가 상품 삭제 기능에서 에러가 발생했다.

기능 하나하나 에러를 잡아가며 구현해왔는데 갑자기 상품 CRUD 부분의 에러라니..! 멘붕이었다.

에러를 확인해보니, item을 삭제할 때 orderItem을 삭제하지 못한다는 뜻인 것 같았다. 주문 취소 기능을 위해 item과 orderItem에 연관관계를 설정해놓은 것이 큰 실수였다.

주문 취소 기능을 위해 새로 매핑한 연관관계가 이전에 구현해놓은 상품 삭제 기능에 영향을 미친 것이다. ㅠㅠ

< ItemService >

// 상품 삭제
    @Transactional
    public void itemDelete(Integer id) {
        // cartItem 중에 해당 id 를 가진 item 찾기
        List<CartItem> items = cartService.findCartItemByItemId(id);

        for(CartItem item : items) {
            cartService.cartItemDelete(item.getId());
        }

        itemRepository.deleteById(id);
    }

주문 취소 기능을 위해 item Entity와 orderItem Entity, saleItem Entity 모두 연관관계를 맺어놨다.

따라서 item을 삭제하기 위해서는 item에 연관되어 있는 orderItem과 saleItem도 삭제되어야 하는데, orderItem은 주문내역을 위해 만들었고 saleItem은 판매내역을 위해 만들었기 때문에 삭제가 되면 안되는 데이터이다.

현재 판매중인 상품이 삭제되더라도 이전에 주문했던 내역과 판매했던 내역은 지워지면 안되기 때문이다.

< Item Entity >

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

@OneToMany(mappedBy = "item")
private List<SaleItem> saleItems = new ArrayList<>();

< OrderItem Entity >

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

< SaleItem Entity >

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

셋의 연관관계를 다 끊어야했다. 그동안 이를 이용해서 기능한 구현들은.. 다 어떻게 되는가.. 엎어야겠지..

우선 주문내역을 구현하기 위해 item으로부터 필요한 정보를 생각해보았다.

  • 상품명, 수량, 가격(수량 * 상품가격), 주문날짜

다음은 판매내역을 구현하기 위해 item으로부터 필요한 정보를 생각해보았다.

  • 상품명, 판매량(수량), 가격, 판매수익, 판매날짜

위의 연관관계 설정을 전부 지우고!
orderItem Entity와 saleItem Entity에 item에 관한 변수를 다시 생성했다.

private int itemId; // 주문 상품 번호
private String itemName; // 주문 상품 이름
private int itemPrice; // 주문 상품 가격
private int itemCount; // 주문 상품 수량
private int itemTotalPrice; // 가격*수량

이에 맞춰서 주문 기능도 수정이 필요하다.
다행히도 생각보다 많은 수정을 필요로 하진 않았다.

기존에는 주문 기능 부분에서 orderItem Entity의 Item에 주문하는 상품인 item 을 Item 형태로 저장해 주었다면,
이제는 item에서 getId(), getName(), getPrice(), getCount()로 꺼내와서 orderItem Entity의 새로 만든 변수들에 넣어주면 된다.

그러면 orderItem Entity에는 Item 형태가 저장되는 것이 아니라, item에서 필요한 정보(상품 이름이나 가격..) 만 꺼내와서 저장했기 때문에 연관관계 없이도 orderItem Entity에 Item에 관한 정보 저장이 가능하게 된다!

즉, 에러가 났던 상품 삭제 기능도 정상작동하게 되었다.

기능 하나를 구현하고자 할 때 그 기능에만 최적화 되도록 구현하려고 하지 말고, 다른 기능들에 영향을 미치는지 잘 살펴보며 구현을 해야한다..

처음에 DB 설계가 정말 중요하다는 것을 뼈저리게 깨달았다.
하필 주문 취소 기능은 프로젝트를 하다가 필요할 것 같아서 내가 갑작스럽게 넣은 기능이라 DB 설계에 없기도 했고, 너무 단순하게 생각했던 부분이다. ㅠㅠ

사실 아직 DB를 설계해놓고 구현을 시작했음에도 불구하고 중간에 수정하기도 하지만.. 객체들의 연관관계를 파악하는 것이 얼마나 중요한지 너무.... 잘.... 알았다....!

0개의 댓글