# 엔티티 설계시 주의점

1. **엔티티에는 가급적 Setter 사용❌**\
   Setter가 모두 열려있으면 변경 포인트가 너무 많아서 유지보수 어렵다!\
   \=>리팩토링 시에 Setter 모두 제거! Setter를 둔다고 해도 의미있는 이름의 메서드로 만들어서 명시적으로 알아보기 쉽게 만든다!
2. @XToOne(OneToOne, ManyToOne) 관계는 기본이 **즉시로딩(EAGER)**&#xC774;므로 **직접 지연로딩(LAZY)으로 설정해야 한 다.⭐️⭐️⭐️⭐️⭐️(**&#x4F;neToMany : LAZY)

   **그렇지 않으면 Order 하나랑 이와 연관된 Member 하나 조회하려고 해도 100개가 조회된다. (N+1(order))** 데이터 하나를 가져오려고 하지만 연관된 데이터들 다 가져오는 문제.\
   이는 곧 JPA 성능 저하로 이어지기 때문에 실무에서는 EAGER 절대 쓰면 안 된다!\
   그런데 LAZY를 못 쓰는 상황이라면?\
   LAZY 로딩는 트랜잭션 밖에서 로딩이 안 되는 이슈가 있다. 이러한 LAZY 로딩 Exception경우에도 EAGER 가 아니라 트랜잭션을 좀 빨리 가져온다거나 상황에 따라서는 open session xxx 같은 다른 대안들이 있다. 궁극적인 해결책은 fetch join으로 해결이 된다고 한다.
3. 컬렉션은 필드에서 초기화 하자!!\
   하이버네이트가 컬렉션을 관리하기 때문에 변경되면 안 된다!\
   컬렉션은 필드에서 바로 초기화 하는 것이 null 문제에서 안전하다.\
   **하이버네이트는 엔티티를 영속화 할 때**, **컬랙션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경**한다. 만약 **getOrders() 처럼 임의의 메서드에서 컬력션을 잘못 생성**하면 **하이버네이트 내부 메커니즘에 문제가 발생**할 수 있다. 따라서 **필드레벨에서 생성**하는 것이 **가장 안전**하고, **코드도 간결**하다.
4. 테이블, 컬럼명 생성 전략 : 스프링 부트에서 하이버네이트 기본 매핑 전략을 변경해서 실제 테이블 필드명은 다름\
   스프링 부트 신규 설정 (엔티티(필드) => 테이블(컬럼))\
   1\. 카멜 케이스 언더스코어(memberPoint member*point)*\
   *2. .(점)* (언더스코어)\
   3\. 대문자 소문자
5. 적용 2단계\
   ① 논리 이름 : **명시적으로 컬럼, 테이블명을 직접 적지 않으면** ImplicitNamingStrategy 사용\
   테이블이나, 컬럼명을 명시하지 않을 때 논리명 적용\
   spring.jpa.hibernate.naming.implicit-strategy&#x20;

   ② 물리 이름 : 모든 논리명에 적용됨, 실제 테이블에 적용\
   spring.jpa.hibernate.naming.physical-strategy\
   ex) 전사적으로 클래스명 앞에 xx를 붙여야할 때
6. 캐스케이드 (cascade=CascadeType.ALL)\
   원래는 엔티티 각각에 대해 persist해야한다. 하지만 캐스케이드를 추가하면 컬렉션에 있는 데이터들 또는 그 엔티티를 모두 함께 다 persist해준다!\
   Order 클래스(테이블) 내에서 orderItems 추가할 때 엔티티 각각에 대해 persist해야한다. 다음과 같이 :\
   persist(orderItemA)\
   persist(orderItemB)\
   persist(orderItemC)\
   persist(order)\
   그런데 orderItems 컬렉션에 @OneToMany(mappedBy="order", cascade=CascadeType.ALL) 추가해주면\
   persist(order) 이렇게만 해주면 된다.
7. 양방향 관계일 때 연관관계 편의 메서드\
   DB 상에서는 한 테이블에서만 데이터 수정 일어나지만 코드상에서 비즈니스 로직구현할 때는 다음처럼 구현할 것이다. 하지만 member, order 둘다 해줘야하는데 한쪽만 하는 경우가 발생하게 된다.

```java
public static void main(String[] args) {
    Member member = new Member();
    Order order = new Order();
    
    member.getOrders().add(order);
    order.setMember(member);
}
```

다음과 같이 Order 클래스 내에서 원자적으로(두 개 동시에 한번에 묶어서!) 처리하는 메서드를 구현하면 된다! Order 클래스 내에서 Member, OrderItem, Delivery 한번에 처리한다.\
(Order\&Member, ORder\&OrderItem, Order\&Delivery)

다음과 같은 메서드는 양방향 중에 핵심적으로 컨트롤을 하는 쪽에 구현하는 것이 좋다!

```java
public void setMember(Member member) {
    this.member = member;
    member.getOrders().add(this);
}

public void addOrderItem(OrderItem orderItem) {
    orderItems.add(orderItem);
    orderItem.setOrder(this);
}

public void setDelivery(Delivery delivery) {
    this.delivery = delivery;
    delivery.setOrder(this);
}
```
