Spring/JPA

실전 예제

Ynghan 2023. 2. 19. 09:36

실전 예제 1. 요구사항 분석과 기본 매핑

요구사항 분석

  • 회원은 상품을 주문할 수 있다.
  • 주문 시 여러 종류의 상품을 선택할 수 있다.

기능 목록

  • 회원 기능
    • 회원 등록
    • 회원 조회
  • 상품 기능
    • 상품 등록
    • 상품 수정
    • 상품 조회
  • 주문 기능
    • 상품 주문
    • 주문내역조회
    • 주문취소

도메인 모델 분석

  • 회원과 주문의 관계 : 회원은 여러 번 주문할 수 있다. (일대다)
  • 주문과 상품의 관계 : 주문할 때 여러 상품을 선택할 수 있다. 반대로 같은 상품도 여러 번 주문될 수 있다.
    주문상품이라는 모델을 만들어서 다대다 관계를 일대다, 다대일 관계로 풀어냄

테이블 설계

엔티티 설계와 매핑

데이터 중심 설계의 문제점

  • 현재 방식은 객체 설계를 테이블 설계에 맞춘 방식
  • 테이블의 외래키를 객체에 그대로 가져옴
  • 객체 그래프 탐색이 불가능
  • 참조가 없으므로 UML도 잘못됨(?)

 

실전 예제 2. 연관관계 매핑 시작

테이블 구조

  • 테이블 구조는 이전과 같다.

객체 구조

  • 참조를 사용하도록 변경

가장 중요한 것은 단방향 연관관계를 정하는 것!

 

실전 예제 3. 다양한 연관관계 매핑

배송, 카테고리 추가 - 엔티티

  • 주문과 배송은 1 : 1 (@OneToOne)
  • 상품과 카테고리는 N : M (@ManyToMany)

ERD

엔티티 상세

 

 

실전 예제 4. 상속관계 매핑

요구사항 추가

  • 상품의 종류는 음반, 도서, 영화가 있고 이후 더 확장될 수 있다.
  • 모든 데이터는 등록일과 수정일이 필수다.

도메인 모델

도메인 모델 상세

Album.java / Book.java / Movie.java

@Entity
public class Book extends  Item {
    private String author;
    private String isbn;

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

Item.java

@Entity
@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;
    
    ...
    
}
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
  • @DisriminatorColumn은 default가 name = "DTYPE"

테이블 설계

 

실전 예제 5 - 연관관계 관리

글로벌 페치 전략 설정

  • 모든 연관관계를 지연 로딩으로
  • @ManyToOne, @OneToOne은 기본이 즉시 로딩이므로 지연 로딩으로 변경

영속성 전이 설정

  • Order -> Delivery를 영속성 전이 ALL 설정
  • Order -> OrderItem을 영속성 전이 ALL 설정

 

Order.java

@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "DELIVERY_ID")
private Delivery delivery;

@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
private List<OrderItem> orderItems = new ArrayList<>();

이렇게 세팅하면 Order를 persist하면 OrderItem과 Delivery가 함께 persist 된다.

 

 

실전 예제 6 - 값 타입 매핑

city, street,zipcode를 Address로 생성

 

Address.java

@Embeddable
public class Address {
    //Address
    private String city;
    private String street;
    private String zipcode;

	...
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Address)) return false;
        Address address = (Address) o;
        return Objects.equals(getCity(), address.getCity()) && Objects.equals(getStreet(), address.getStreet()) && Objects.equals(getZipcode(), address.getZipcode());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getCity(), getStreet(), getZipcode());
    }
    
    ...
  • equals와 hashCode는 프록시를 고려하여 getter 메소드를 사용하여 접근한다.
    다른 메소드들도 대부분 이런식으로 한다.

Member.java

@Entity
public class Member {
    
    ...

    @Embedded
    private Address address;
    
    ...

Delivery.java

@Entity
public class Delivery extends BaseEntity {
    
    ...
    
    @Embedded
    private Address address;
    private DeliveryStatus status;

    ...

Address.java

@Embeddable
public class Address {
    //Address
    private String city;
    private String street;
    private String zipcode;

    public Address() {
    }

    public Address(String city, String street, String zipcode) {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }
    
    ...

'Spring > JPA' 카테고리의 다른 글

다양한 연관관계 매핑  (0) 2023.02.22
연관관계 매핑 기초  (0) 2023.02.19
엔티티 매핑  (0) 2023.02.19
영속성 관리 - 내부 동작 방식  (0) 2023.02.18
JPA 애플리케이션 개발  (0) 2023.02.18