출처: 스프링 부트 핵심 가이드 - 장정우 지음
https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=296591989
설계가 복잡해지면 각 도메인에 맞는 테이블을 설계하고 연관관계를 설정해서 Join등의 기능을 활용하게 된다.
JPA를 사용하는 어플리케이션에서도 테이블의 연관관계를 엔티티의 연관관계로 표현할 수 있다!
다만 객체와 테이블은 성질이 다르기 때문에 정확한 연관관계를 표현할 수는 없다.
어떤 엔티티를 중심으로 연관 엔티티를 보느냐에 따라 연관관계의 상태가 달라진다.
One to One (일대일)
One to Many (일대다)
Many to One (다대일)
Many to Many (다대다)
예시 )
공급입장에서는 여러 상품을 남품할 수 있으므로 → 일대다
상품입장에서는 하나의 공급업체에 속하므로 → 다대일

데이터베이스 :
JPA를 사용하는 객체지향 모델링 :
JPA: 객체에서 양방향 개념은 양쪽에서 단방향으로 서로 매핑하는 것
연관관계가 설정되면 한테이블에서 다른테이블의 기본값을 외래키로 가짐
하나의 상픔에 하나의 상품정보만 매핑되는 구조
상품 정보 엔티티에서 상품필드에 @OneToOne어노테이션과 @JoinColumn(name = "product_number") 어노테이션을 붙인다.
@OneToOne :
다른 엔티티 객체(여기서는 상품)를 필드로 정의 했을때, 일대일 연관관계로 매핑하기위해 사용
조회 시 Hibernate구문을 보면 상품과 상품 정보 left join이 사용됨
엔티티 조회 시, 연관된 엔티티도 함께 조회(즉시 로딩)
그 이유는 @OneToOne 의 기본 fetch() 전략이 EAGER 즉, 즉시 로딩이기 때문
@OneToOne의 optional() 메소드 : 기본값은 true로, 매핑되는 값이 nullable이라는 뜻이다.
@OneToOne(optional = false)를 추가@JoinColumn(name = "product_number") :
매핑할 외래키 설정
기본값이 설정되어 있어 자동으로 이름을 매핑하지만 name 속성을 사용해 원하는 칼럼명을 지정하는 것이 좋다.
@JoinColumn을 선언하지 않으면 엔티티를 매핑하는 중간 테이블이 생가면서 관리 포인트가 늘어나 좋지 않음!!!
속성 :


앞서 상품정보 엔티티에 @OneToOne, @JoinColumn 어노테이션을 붙여주었으므로 상대 엔티티인 상품 엔티티의 상품정보 필드에 @OneToOne를 붙여준다.
mappedBy : 어떤 객체가 주인인지 표시하는 속성!!
엔티티는 양방향으로 매핑하되 한쪽에게만 외래키를 주기
@OneToOne(mappedBy="상품")으로 바꿔준다따라서 필요한 경우가 아니라면, 대체로 단방향으로 연관관계 설정!!
양방향 설정이 필요한 경우, 순환참조 제거를 위해 exclude를 사용하여 toString에서 제외 설정 필요!
@ToString.Exclude어노테이션을 상품 엔티티의 상품 정보 필드에 붙임!


@ManyToOne어노테이션 추가!@JoinColumn(name="provider_id") 어노테이션 추가!@ToString.Exclude어노테이션 추가!
반대로 공급업체를 통해 상품을 조회하기 위해 일대다 연관관계 설정
공급업체 엔티티의 상품필드에 @OneToMany 어노테이션 추가
@OneToMany의 기본 fetch전략은 lazy이다. 지연로딩과 즉시 로딩
엔티티라는 객체의 개념으로 데이터베이스를 구현했으므로 연관관계를 가진 각 엔티티 클래스에는 연관관계가 있는 객체들이 필드에 존재하게 됨!
지연로딩: 연관관계와 상관없이 즉각 해당 엔티티의 값만 조회하고 싶을때
즉시로딩: 연관관계를 가진 테이블의 값도 조회하고 싶을때
순환참조 방지를 위해 @ToString.Exclude 어노테이션 추가
일대다 연관관계의 경우 여러 엔티티가 포함될 수 있으므로 컬랙션(Collections, List, Map) 형식으로 필드생성
주인인 상품엔티티에 외래키 관리 위임을 위해 @OneToMany(mappedBy="provider) 설정
공급업체 엔티티는 주인이 아니라서 외래키 관리 불가!
따라서 공급업체를 등록한 후 각 상품 객체에 설정하는 작업을 통해 데이터 베이스에 저장
공급업체 엔티티에서 정의한 productList필드에 상품 객체를 추가하는 방식으로 데이터 베이스에 레코드를 저장하게 되면 해당 데이터는 DB에 반영 안됨!
주인은 상품 엔티티이다.
따라서 공급업체 엔티티 클래스를 수정해도 어플리케이션을 가동해보면 칼럼은 변경되지 않는다.
즉, mappedBy로 설정된 필드는 칼럼에 적용되지 않는다!
양쪽에서 연관관계를 설정하고 있을때, RDBMS 형식처럼 사용하기 위해 mappedBy를 통해 외래키 관리 위임~!!!


@OneToMany, @JoinColumn을 사용하면 상품 엔티티에서 별도의 설정을 하지 않아도 일대다 단방향 연관관계 매핑 됨.
@JoinColumn은 앞에서 말했다시피 필수가 아님! 이 어노테이션을 사용하지 않으면 중간 테이블로 Join테이블이 생성되는 전략이 채택됨.
일대다 단방향 관계에서는 다대일 구조와 다르게 외래키를 설정하기 위해 다른 테이블에 대한 update쿼리를 발생시킴
따라서 일대다 양방향 연관관계를 사용하기 보다 다대일 연관관계를 사용하는 것이 좋음!!


@ManyToMany어노테이션 사용@JoinColumn 설정할 필요 ❌ @JoinTable(name="")으로 중간테이블이름을 정해줄 수 있음
상품엔티티에도 @ManyToMany어노테이션 사용
필요에 따라 mappedBy속성으로 주인 설정
이렇게 설정하고 어플리케이션을 실행해도 데이터베이스의 테이블 구조는 변경 ❌
중간테이블이 연관관계를 설정하고 있기 때문!!!
다대다 연관관계를 설정하면 중간 테이블을 통해 연관된 엔티티의 값을 가져옴
그러나 다대다 연관관계에서는 중간테이블이 생성되기 때문에 예기치 못한 쿼리가 생길 수 있음!!
즉, 관리가 힘든 포인트가 발생하는 문제점!!
해결: 중간 테이블 생성 대신 일대다 다대일로 연관관계를 맺을 수 있는 중간 테이블로 승격시켜 JPA에서 관리할 수 있도록 생성하자!
양방향으로 연관관계가 설정되면, toString을 사용할때 순환참조 발생!!
따라서 필요한 경우가 아니라면 대체로 단방향으로 연관관계 설정!!
순환참조 제거를 위해 exclude를 사용하여 toString에서 제외 설정 필요!- @ToString.Exclude 를 한 엔티티의 필드에 붙여줌
@OneToMany(mappedBy="provider", cascade = CascadeType.PERSIST)@OneToMany(mappedBy="provider", cascade = CascadeType.PERSIST, orphanRemoval true)