Notice
Recent Posts
Recent Comments
Link
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

엔티티 클래스 개발 본문

인프런/[인프런] Springboot와 JPA활용 1

엔티티 클래스 개발

Seung__ 2021. 8. 5. 22:00

1. 엔티티 클래스 개발 시 주의사항(Getter, Setter), 참고


  • 이론적으로 Getter, Setter 모두 제공하지 않고, 꼭 필요한 별도의 메서드를 제공하는게 가장 이상적.
  • Getter의 경우 모두 열어두는 것이 편리하다.
  • Getter는 아무리 호출해도 호출 해도 값이 변하거나 무슨 일이 일어나지 않는다.
  • 하지만  Setter를 호출하면 데이터가 변한다.
  • Setter를 막 열어두면 엔티티가 왜? 변경되는지 추적하기 어려움
  • 그래서 엔티티를 변경할 때는 Setter 대신에 변경 지점이 명확 하도록
  • 변경을 위한 비즈니스 메서드를 별도로 제공해야 한다
  • 테이블은 관례상 테이블명+id로 사용함. 그래서 column(name="필드명_id")로 했음.

 

2. 일대다, 다대일


  • many측에 FK가 있음. many측이 연관관계 주인.
  • many측에서 one을 변경하면 FK 변경됨
  • one측은 many를 변경할 수 없음. List<many>를 읽어오기만 함.
  • 회원과 주문은 일대다 관계, 주문 측에 회원 FK있음. 주문이 연관관계 주인.
  • 주문 측에서 member를 변경하면 FK 변경됨.
  • 회원은 order를 단순히 읽어오기만 함. order를 변경하지 못함.
  • Order class
    - @ManyToOne
    - @JoinColumn(name = "member_id") -> 회원 PK를 FK로 가지고 있음. 엔티티와 테이블을 FK로 매핑.

    @Entity
    @Table(name="orders")
    @Getter
    public class Order {
    
        @Id
        @GeneratedValue
        @Column(name = "order_id")
        private Long id;
    
        @ManyToOne
        @JoinColumn(name = "member_id")
        private Member member;
    
        @OneToMany(mappedBy = "order") //order_item의 어느 컬럼으로부터 orderItem 읽어옴?
        private List<OrderItem> orderItems = new ArrayList<>();
    
        @OneToOne
        @JoinColumn(name = "delivery_id")
        private Delivery delivery;
    
        private LocalDateTime orderDate; //주문 시간
    
        @Enumerated(EnumType.STRING)
        private OrderStatus status; //주문상태, enum
    
    
    }​
  • Member class
    - @OneToMany(mappedBy = "member")
    - mappedBy :  내가 many측 어떤 column에 매핑됨?
    - member는 order table의 member clumn로부터 매핑됨. 
    @Entity
    @Getter
    @Setter
    public class Member {
    
        @Id
        @GeneratedValue
        @Column(name="member_id")
        private Long id;
    
        private String name;
    
        @Embedded
        private Address address;
    
        @OneToMany(mappedBy = "member") //mappedBy쓰면 단순히 맵핑된다는 의미. 읽어오기만함. 주인 아님.
        private List<Order> orders = new ArrayList<>();
    }​

 

3. 일대일


  • 일대일의 경우 FK는 어느 곳에 있어도 상관 없음.
  • FK가 있는 곳이 연관관계 주인.
  • 주문과 배송은 일대일 관계
  • FK는 주문에 있음. 주문은 배송PK를 FK로 가지고 있음. 주문이 연관관계 주인.
  • Order class
    - @OneToOne
    - @JoinColumn(name = "delivery_id")
    @Entity
    @Table(name="orders")
    @Getter
    public class Order {
    
        @Id
        @GeneratedValue
        @Column(name = "order_id")
        private Long id;
    
        @ManyToOne
        @JoinColumn(name = "member_id")
        private Member member;
    
        @OneToMany(mappedBy = "order") //order_item의 어느 컬럼으로부터 orderItem 읽어옴?
        private List<OrderItem> orderItems = new ArrayList<>();
    
        @OneToOne
        @JoinColumn(name = "delivery_id")
        private Delivery delivery;
    
        private LocalDateTime orderDate; //주문 시간
    
        @Enumerated(EnumType.STRING)
        private OrderStatus status; //주문상태, enum
    
    
    }​
  • Delivery class
    - @OneToOne(mappedBy = "delivery")
    @Entity
    @Getter @Setter
    public class Delivery {
        @Id
        @GeneratedValue
        @Column(name = "delivery_id")
        private Long id;
    
        @OneToOne(mappedBy = "delivery") //Order table의 어느 컬럼에서 읽어옴???
        private Order order;
    
        @Embedded
        private Address address;
    
        @Enumerated(EnumType.STRING) //ORDINAL 은 0 1 2 3 숫자로 들어감. 중간에 다른 상태 추가되면 난리남. 숫자 매칭이 달라짐.
        private DeliveryStatus status; //READY, COMP
    
    }​

 

5. 다대다


  • 실무에서는 @ManyToMany사용 안함
  • @ManyToMany 사용 시 중간 테이블 필요함
  • 중간 테이블은 값을 추가한다거나 할 수 없음.
  • 중간 테이블은 양 측 FK를 가지고 있음. 
  • 객체는 양쪽에 collection, collection으로 다대다 구현 가능
  • 하지만 관계형 DB는 불가능하니 중간 테이블 필요함.
  • Category class
    - @JoinTable(name = "중간table 명"),
          joinColumns = @Joincolumn(name = "category_id"), //카테고리 클래스랑 매핑되는 FK
          inverseJoinColumns = @JoinColumn(name = "item_id")) //item 측에서 매핑되는 FK.
    @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"))//item 쪽으로
        private List<Item> items = new ArrayList<>();
    
        @ManyToOne
        @JoinColumn(name = "parent_id")
        private Category parent;
    
        @OneToMany(mappedBy = "parent") //child 입장(엔티티)에서 parent
        private List<Category> child = new ArrayList<>();
    }​
  • Item class
    - @ManyToMany(mappedBy = "items") //카테고리의 어느 컬럼에서 매핑됨?
    @Entity
    @Getter
    @Setter
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "dtype")
    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<>();
    
    
    
    }​
     
  • 하지만 실무에서는 @ManyToMany 안씀!!!!
  • 중간 엔티티를 만들어 1:N, N:1로 풀어서 해결하자.

 

 

6. 계층구조


  • Category는 계층 구조를 가지고 있다. (parent, child)
  • Parent와 Child는 결국 일대다 관계이다.
  • Parent와 다대일
    - @ManyToOne
    - @JoinColumn(name = "parent_id") : parent의 PK를 FK로 가지고 있음..
  • child와 일대다
    - @OneToMany(mappedBy = "parent") : 내가 child의 어느컬럼에서 매핑됨?
        @ManyToOne
        @JoinColumn(name = "parent_id")
        private Category parent;
    
        @OneToMany(mappedBy = "parent") //child 입장(엔티티)에서 parent
        private List<Category> child = new ArrayList<>();​

 

💥'21.08.17 추가사항


  • 계층 구조를 가질 때, @JoinColumn(name = "catetory_id")가 아니라 "paretn_id" column에 조인한다..?
  • parent_id라는 컬럼은 없는데...?
  • 범인은 @JoinColumn의 referencedColumnName()이다.
  • referencedColumnName()을 별도 지정하지 않으면 referenced Table(매핑하는 테이블)의 PK를 지정함.
  • 즉, "parent_id"는 FK의 이름이고 이는 Category parent의  PK인 category_id를 가르키게 된다.
Default : The same name as the primary key column of the referenced table.
  • @JoinColumn(name ="")의 name은 내 테이블의 FK의 이름이고 FK가 가르키는 값은 referencedColuName()을 별도 지정하지 않는 한 referenceTable(매핑하는 테이블)의 PK를 지정함

 

7.값 타입, embedded Type


 

 

Embedded

Embedded 타입이란? 값 타입의 일종으로 복합 값 타입으로 이해하면 된다. 값 타입이란 값 타입은 int, Integer, String과 같이 값을 가지고 있는 타입들이 속한다. Embedded type은 여러개의 값을 묶어서 하

bsh-developer.tistory.com

  • 변경이 불가능하게 설계해야 함.
  • @Setter를 제거하고, 생성자에서 값을 모두 초기화해서 변경 불가능한 클래스 만들어야함.
  • JPA 스펙상 임베디드타입은 기본 생성자는 public 또는 protected로 설정해야 한다.
  • public 보다는 protected로 해야 그나마 안전함.
  • JPA가 구현 라이브러리가 객체를 생성할 때 리플렉션 같은 기술을 사용하도록 지원필요함.
  • Address class
    @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;
        }
    }​
  • Member class : embedded 타입 사용처
    @Entity
    @Getter
    @Setter
    public class Member {
    
        @Id
        @GeneratedValue
        @Column(name="member_id")
        private Long id;
    
        private String name;
    
        @Embedded
        private Address address;
    
        @OneToMany(mappedBy = "member") //mappedBy쓰면 단순히 맵핑된다는 의미. 읽어오기만함. 주인 아님.
        private List<Order> orders = new ArrayList<>();
    }​

8. enum 사용시 주의사항


  • EnumType 
    - ORDINAL : enum이 숫자로 들어감. 중간에 새로운 타입이 추가되면 매핑되는 숫자가 달라짐.
    - STRING : string으로 들어가면 중간에 타입이 추가되어도 들어가는 값이 달라지지 않음.
  • 항상 STRING으로 사용하자.
    @Enumerated(EnumType.STRING) //ORDINAL 은 0 1 2 3 숫자로 들어감. 중간에 다른 상태 추가되면 난리남. 숫자 매칭이 달라짐.
    private DeliveryStatus status; //READY, COMP

 

9. 상속관계 매핑.


  • @Inheritance(strategy = InheriatanceType.~~)
    - JOINED : 조인 전략
    - SINGLE_TABLE : 단일 테이블 전략 -> 하나의 테이블로 관리
    - TABLE_PER_CLASS : 구현 클래스마다 테이블 전략
  • @DiscriminatorColumn(name = "dtype")
    - 테이블만 보면 하위 엔티티들을 구분할 수 있는 방법이 없다.
    - dtype을 통해 하위 엔티티들이 가진 값으로 구분이 가능하다.
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "dtype")
    public abstract class Item {​
  • @DiscriminatorValue("~")
    - @DiscriminatorColumn을 설정하면
    - 하위 클래스에 dtype 지정이 가능하다.

    - 이를 통해 singleTable로 관리해도 하위 엔티티들을 구분할 수 있다.
    - 기본은 필드명이나 변경도 가능하다.
    @DiscriminatorValue("M")
    public class Movie extends Item{

 

10. 실행 결과


  • DB에 table이 잘 생성되었당.

 

 

11. GitHub : 210805 Entity class


 

GitHub - bsh6463/SpringBootJPA1

Contribute to bsh6463/SpringBootJPA1 development by creating an account on GitHub.

github.com

 

 

12. AlterTable


  • alter Table : 테이블 수정
  • 테이블 수정을 통해 FK를 엮어줌 ㅋㅋ
  alter table category_item 
       add constraint FKb6464ojqmu6ykwmjoq5pl72rd 
       foreign key (category_id) 
       references item

'인프런 > [인프런] Springboot와 JPA활용 1' 카테고리의 다른 글

회원 도메인 개발  (0) 2021.08.06
엔티티 설계 시 주의점  (0) 2021.08.06
도메인 모델 , 테이블 설계  (0) 2021.08.05
도메인 분석 설계  (0) 2021.08.05
JPA, DB 설정 및 실행하기  (0) 2021.08.05
Comments