Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
Tags
- 김영한
- java
- Proxy
- spring
- 스프링 핵심 기능
- Servlet
- 스프링 핵심 원리
- transaction
- pointcut
- QueryDSL
- kotlin
- 백준
- SpringBoot
- Android
- JDBC
- Spring Boot
- http
- JPQL
- 스프링
- 자바
- AOP
- Thymeleaf
- 그리디
- 인프런
- Exception
- jpa
- springdatajpa
- 알고리즘
- Greedy
- db
Archives
- Today
- Total
개발자되기 프로젝트
엔티티 클래스 개발 본문
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
- 변경이 불가능하게 설계해야 함.
- @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
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