도메인 분석 설계(복습)

박경희·2025년 1월 15일
0

강의 복습 및 정리

목록 보기
30/38

참고-실전! 스프링 부트와 JPA활용1 -웹 어플리케이션 개발

설계된 것을 보고 먼저 설계 후 강의를 들어봤는데 계속 빼먹는 부분이들이 있어 메모🗒️

컬렉션은 필드에서 초기화 하자

	@OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
  • 컬렉션은 필드에서 초기화 하는 것이 안전하다.
  • new ArrayList<>(); 빼먹지 말자!
    -> 초기화에 대해 고민하지 않아도 된다.
    -> null point exception 이 나지 않는다.(null 문제에서 안전)
  • 하이버네이트는 엔티티를 영속화 할 때, 컬렉션을 감싸서 하이버네이트가 제공하는 내장 컬렉션으로 변경한다.
Member member = new Member();
 System.out.println(member.getOrders().getClass());
 em.persist(member);
 System.out.println(member.getOrders().getClass());
//출력 결과
 class java.util.ArrayList
 class org.hibernate.collection.internal.PersistentBag
  • 만약 getOrders() 처럼 임의의 메서드에서 컬렉션을 잘못 생성하면 하이버네이트 내부 메커니즘에 문제가 발생할 수 있다. 따라서 필드레벨에서 생성하는 것이 가장 안전하고, 코드도 간결하다.

	@Id @GeneratedValue
    @Column(name = "member_id")
    private Long id;
  • pk값을 잘 넣어주자. @Column(name = "member_id") ⭐️

내장 타입은 @Embeddable

	@Embeddable
	@Getter
	public class Address { //값타입은 변경 불가능하게 설계해야 한다.
    private String city;
    private String street;
    private String zipcode;

사용하는 곳에는 @Embedded

	@Embedded
    private Address address;

Joincolumn(name = "")

  • mappedBy만 생각하지 말고 Joincolumn도 꼭 기억하자!!

추상 클래스 설계 (abstract)

public abstract class Item {

  • 이 부분은 어떻게 설계 할지 몰라 강의를 보며 다시 배웠다.
  • Item을 추상 클래스로 만들고 Album, Book, Movie는 상속 받아 사용하도록 해야 한다.
  • 상속관계 전략을 부모 클래스에 잡아줘야 한다.
  • 여기서는 싱글 클래스 전략을 사용했다.
@Entity
@Getter @Setter
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "dtype")```
코드를 입력하세요

public abstract class Item {

- 부모클래스에 `@Inheritance(strategy = InheritanceType.SINGLE_TABLE)` 를 넣어준다.
- 싱글테이블 전략이기 때문에 album, book, movie를 구별할 수 있게 해줘야 한다.
`@DiscriminatorColumn(name = "dtype")` 을 부모테이블에 넣어 준다.

- 자식 클래스에 아무것도 넣지 않으면 기본 클래스 이름으로 `dtype`이 반영되지만 명칭을 줄 수 있다.
`@DiscriminatorValue("B")`

---

###  <span style="color:coral">enum 타입</span>

⭐️ enum 타입은 사용하는 곳에 꼭 `@Enumerated(EnumType.STRING)` 넣어줘야 한다.

```java
 	@Enumerated(EnumType.STRING)
    private DeliveryStatus status;
  • 기본이 ORDINAL인데 이대로 사용하면 나중에 추가로 다른 상품 같은게 추가될 때 순서가 밀려서 꼬일 수 있다.

일대다 다대일 (ManyToMany) 풀어내기

(실무에서는 사용하지 않는다.)

  • 각 값을 가진 클래스를 따로 만드는게 아니다.
public class Category

	@ManyToMany
	@JoinTable(name = "category_item",
        joinColumns = @JoinColumn(name = "category_id"),
        inverseJoinColumns = @JoinColumn(name = "item_id"))
	private List<Item> items = new ArrayList<>();
  • 중간 테이블 매핑 : JoinTable(name = ""category_item)
  • 중간 테이블의 카테고리 아이디 : joinColumns = @JoinColumn(name = "category_id")
  • category_item 테이블에서 item 쪽으로 들어가는 부분 :
    inverseJoinColumns = @JoinColumn(name = "item_id")

반대편 ManyToMany

	@ManyToMany(mappedBy = "items")
    private List<Category> categories = new ArrayList<>();
  • 다른 연관관계 맺는 것과 마찬가지로 mappedBy 해주면 된다.

셀프 연관관계

  • 처음에는 왜 만드는 건가 하는 의문이 들어 찾아봤다.
  • "의류" 카테고리의 하위에 "남성 의류"와 "여성 의류" 카테고리를 하위, 또 그 하위에 세부 항목을 배치할 수 있다.
    이런식으로 쓰기 위해서 사용하는 것 같다.
public class Category {

 	@ManyToOne //내 부모니까 manyToOne
    @JoinColumn(name = "parent_id")
    private Category parent;

    @OneToMany(mappedBy = "parent")
    private List<Category> child = new ArrayList<>();
  • Category 안에서 셀프로 양방향 연관관계를 만든 것이다.

cascade = CascadeType.ALL

public class Order {
	@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
    private List<OrderItem> orderItems = new ArrayList<>();
  • cascade = CascadeType.ALL 은 persist를 전파한다.
    예를 들어 OrderItem에 orderItemA, B, C를 담아놨다고 하자.
    원래는 각각 다 persist를 해줘야 하지만 cascade = CascadeType.ALL 하면 persist(order)하나 만으로 모두 persist 된다.
  • All 이기 때문에 delete할 때도 다 지워버린다.
public class Order {

	@OneToOne(fetch = LAZY, cascade = ALL)
    @JoinColumn(name = "delivery_id")
    private Delivery delivery;
  • delivery에 값을 세팅해두고 order를 persist 하면 delivery도 같이 persist 된다.
    원래 모든건 각각 해줘야 하는데 cascade가 해준다.

값 타입 -변경 불가능하게 설계해야 한다.

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;
    }
  • 기본 생성자 보면 : JPA 스펙상 만들어둔 거구나~
    public을 마구 호출하지 못하도록 protected로 설정. '함부로 new하면 안되겠네~'
    하도록.

0개의 댓글