[자바 ORM 표준 JPA 프로그래밍 - 기본편] 06. 다양한 연관관계 매핑

Turtle·2024년 6월 18일
0
post-thumbnail

🙄연관관계 매핑시 고려사항 3가지

  • 다중성
  • 단방향, 양방향
  • 연관관계의 주인

🙄다대일(N:1)👍

  • ✔️다대일 단방향 정리
    • 일반적으로 N(다)쪽에서 외래 키를 관리함
    • 연관관계의 주인 : N(다)
    • 회원에서 팀으로의 조회만 가능
    • 이 회원이 어떤 팀에 속해있는지
@Entity
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String name;
	
    ///////////////////////////////// 핵심 코드(다대일 단방향)
    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
	/////////////////////////////////
}

  • ✔️다대일 양방향 정리
    • 연관관계의 주인 : N(다)
    • 팀에서 회원으로의 조회도 가능
    • 해당 팀에 어떤 회원들이 있는지
    • 양쪽을 서로 참조하도록 개발
@Entity
public class Team {
    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
    
    ///////////////////////////////// 핵심 코드(다대일 양방향)
    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>();
    /////////////////////////////////
}

🙄일대다(1:N)

  • ✔️일대다 단방향 정리
    • 일대다 단방향은 1(일)이 연관관계의 주인
    • 일대다 단방향 매핑 단점
      • 엔티티가 관리하는 외래 키가 다른 테이블에 있음
      • 연관관계 관리를 위해 추가로 UPDATE SQL문이 실행됨
    • 일대다 단방향보다는 다대일 양방향을 사용할 것
@Entity
public class Team {
    @Id
    @GeneratedValue
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
    
    /////////////////////////////////
    @OneToMany
    @JoinColumn(name = "team")
    private List<Member> members = new ArrayList<>();
    /////////////////////////////////
}

실행 결과

Hibernate: 
    /* insert for
        org.example.Member */insert 
    into
        Member (name, team_TEAM_ID, MEMBER_ID) 
    values
        (?, ?, ?)
Hibernate: 
    /* insert for
        org.example.Team */insert 
    into
        Team (name, TEAM_ID) 
    values
        (?, ?)
Hibernate: 
    update
        Member 
    set
        team=? 
    where
        MEMBER_ID=?
  • ✔️일대다 양방향 정리
    • 공식적으로 존재하지 않음
    • 다대일 양방향을 사용

🙄일대일(1:1)

  • ✔️일대일 정리
    • 주 테이블과 대상 테이블의 기준
      • Ex. 게시판, 첨부파일이 있다고 가정
      • 게시판이 주, 첨부파일이 대상
      • 비즈니스 관점에서 실제 개발을 해보아야 주 테이블이 정해진다.
    • 주 테이블에 외래 키
      • 주 객체가 대상 객체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
      • 객체지향 개발자 선호
      • JPA 매핑이 편리
      • 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인이 가능
      • 값이 없으면 외래 키에 null을 허용
    • 대상 테이블에 외래 키
      • 대상 테이블에 외래 키 존재
      • 전통적인 데이터베이스 개발자 선호
      • 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 구조 유지 가능
      • 프록시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩됨

🙄다대다(N:M)

  • ✔️다대다 정리
    • 실무에서 사용X
    • 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음
    • 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야함
    • @ManyToMany 어노테이션 사용
    • @JoinTable로 연결 테이블 지정
  • ✔️다대다 한계 극복
    • 연결 테이블용 엔티티 추가
    • @ManyToMany → @OneToMany, @ManyToOne

🙄연관관계 매핑 실전 예제

  • ✔️요구사항 추가
    • 상품을 주문할 때 배송 정보를 입력할 수 있다. 주문과 배송은 일대일 관계다.
    • 상품을 카테고리로 구분할 수 있다. 상품과 카테고리는 다대다 관계다.

  • ✔️계층형 카테고리 부분
    • 부모-자식 또는 계층 관계에서의 설정
      • Ex1. 전체 - 상의 - 아우터, 티셔츠, 맨투맨
      • Ex2. 전체 - 하의 - 청바지, 슬랙스, 반바지
    • 중간 카테고리인 상의를 기준으로 상의 부모는 전체 하나(1)
    • 중간 카테고리인 상의를 기준으로 상의 자식은 아우터, 티셔츠, 맨투맨 여러 개(N)
    • 자신과 자신의 부모에 대해서는 N : 1(다대일, @ManyToOne 어노테이션 사용)
    • 자신과 자신의 자식에 대해서는 1 : N(일대다, @OneToMany 어노테이션 사용)
  • ✔️카테고리 - 아이템
    • 다대다 관계
@Entity
public class Category {
    @Id @GeneratedValue
    private Long id;
    private String name;

	//////////////////////////////////////////////////// 다대다 핵심 코드
    @ManyToMany
    @JoinTable(name = "CATEGORY_ITEM",
        joinColumns = @JoinColumn(name = "CATEGORY_ID"),
        inverseJoinColumns = @JoinColumn(name = "ITEM_ID"))
    private List<Item> items = new ArrayList<>();
	////////////////////////////////////////////////////

	//////////////////////////////////////////////////// 카테고리
	@ManyToOne
	@JoinColumn(name = "PARENT_ID")
	private Category parent;

	@OneToMany(mappedBy = "parent")
	private List<Category> child = new ArrayList<>();
    ////////////////////////////////////////////////////
}
@Entity
public 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<>();
    ////////////////////////////////////////////////////
}
  • ✔️배송 - 주문
    • 일대일 관계
@Entity
@Table(name = "ORDERS")
public class Order {
    @Id @GeneratedValue
    @Column(name = "ORDER_ID")
    private Long id;
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

	////////////////////////////////////////////////////
    @OneToOne // 외래 키를 Order가 소유
    @JoinColumn(name = "DELIVERY_ID")
    private Delivery delivery;
    ////////////////////////////////////////////////////

    private LocalDateTime orderDate;
    @Enumerated(EnumType.STRING)
    private OrderStatus status;

    @OneToMany(mappedBy = "order")
    private List<OrderItem> orderItems = new ArrayList<>();

    public void addOrderItem(OrderItem orderItem) {
        orderItems.add(orderItem);
        orderItem.setOrder(this);
    }
}
@Entity
public class Delivery {
    @Id @GeneratedValue
    private Long id;

	////////////////////////////////////////////////////
    @OneToOne(mappedBy = "delivery")
    private Order order;
    ////////////////////////////////////////////////////

    private String city;
    private String street;
    private String zipcode;
    private DeliveryStatus status;
}

0개의 댓글