Spring/SpringBoot

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

느리지만 꾸준하게 2022. 4. 2. 20:13

Item 폴더안에 Category Class를 만들고

// Category Class

package jpabook.jpashop.domain.item;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

import static javax.persistence.FetchType.*;

@Entity
@Getter @Setter
public class Category {

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

    private String name;


// Category와 item은 다 : 다 관계이다.
    @ManyToMany
    // 중간 테이블 매핑을 해주기 때문에 JoinTable을 넣어준다.(1:다 , 다:1로 풀어내는 중간테이블)
    @JoinTable(name = "category_item",
            joinColumns = @JoinColumn(name = "category_id"),
            inverseJoinColumns = @JoinColumn(name = "item_id"))
	// Item 쪽은 mappedBy로 지정해준다.
    private List<Item> items = new ArrayList<>();

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

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

}

n:n을 1:n, n,1로 풀어내는 중간테이블 CATEGORY_ITEM

 

// Item

package jpabook.jpashop.domain.item;


import jpabook.jpashop.exception.NotEnoughStockException;
import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
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> categories = new ArrayList<>();
    }

카테고리 계층구조를 위해서 아래와 같이 지정을 해주자.

// Category Class

@ManyToMany
    @JoinTable(name = "category_item",
            joinColumns = @JoinColumn(name = "category_id"),
            inverseJoinColumns = @JoinColumn(name = "item_id"))
    private List<Item> items = new ArrayList<>();

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

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

 

JpaApplication을 실행시켜보면 터미널에 테이블이 생성된다.

(단, 터미널에서 생성된 테이블들은 그대로 쓰면 안된다. 참고해서 DDL Script를 다듬고 검증해서 써야한다.)

h2 데이터베이스에도 컬럼들이 생성된다.

 

이제 엔티티 클래스 개발부분을 한번 살펴보자.

 

Setter를 호출하면 데이터가 변경이 되어버린다. 그래서 Setter를 엄청 많이 열어두면 엔티티가 나중에 어떻게 수정이 되는지 파악이 안된다. 여러 서비스에서 엔티티를 바꿔버리고 호출하고 있으면 혼란이 오게된다.

Setter를 막 열어두고 아무데서나 set을 쓰게된다? 그러면 나중에 어플리케이션 변경할 때 매우 불편함을 느끼게 된다.

 

 

 

그리고 ManyToMany를 쓰지말자. 왜냐 중간테이블에 값을 더 넣을 수가 없어서 그렇다.

  • @ManyToMany 는 편리한 것 같지만, 중간 테이블( CATEGORY_ITEM )에 컬럼을 추가할 수 없고,
  • 세밀하게 쿼 리를 실행하기 어렵기 때문에 실무에서 사용하기에는 한계가 있다. 중간 엔티티( CategoryItem 를 만들고
  • @ManyToOne , @OneToMany 로 매핑해서 사용하자. 정리하면 대다대 매핑을 일대다, 다대일 매핑으로 풀어 내서 사용하자.

ManyToMany를 쓰면 수정이라도 들어가는 상황이 생기면 할 수 없게 된다.

 

그리고 Address Class 부분에서 Protected를 넣어주어서 상속을 함부로 하지말고 new로 생성하면 안되겠네라고 생각하면 된다.

아래 부분을 참고하자.

참고!! 값 타입은 변경 불가능하게 설계해야 한다.


@Setter 를 제거하고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스를 만들자. 
JPA 스펙상 엔티티나임베디드 타입( @Embeddable )은 자바 기본 생성자(default constructor)를 public 또는 protected 로 설정해야 한다. 
public 으로 두는 것 보다는 protected 로 설정하는 것이 그나마 더 안전 하다.

 

// Address Class

package jpabook.jpashop.domain;

import lombok.Getter;

import javax.persistence.Embeddable;


@Embeddable
@Getter
public class Address {

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


    protected Address() {
    }



	// public으로 열려있으니까 얘를 써야겠다고 생각할 수 있다.
    public Address(String city, String street, String zipcode) {

        this.city = city;
        this.street = street;
        this.zipcode = zipcode;

    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

<출처 김영한: 실전! 스프링 부트와 JPA 활용1 - 웹 어플리케이션 개발 >

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-%ED%99%9C%EC%9A%A9-1/dashboard

 

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발 - 인프런 | 강의

실무에 가까운 예제로, 스프링 부트와 JPA를 활용해서 웹 애플리케이션을 설계하고 개발합니다. 이 과정을 통해 스프링 부트와 JPA를 실무에서 어떻게 활용해야 하는지 이해할 수 있습니다., - 강

www.inflearn.com