JPA - 다양한 연관관계 매핑

노력하는 배짱이·2022년 7월 31일
0

JPA

목록 보기
5/9

연관관계 매핑시 고려사항

  1. 다중성
    -> 다대일, 일대다, 일대일, 다대다
  2. 단방향, 양방향
  3. 연관관계의 주인

단방향, 양방향

  • 테이블
    -> 외래키 하나로 양쪽 조인 가능

  • 객체
    -> 참조용 필드가 있는 쪽으로만 참조 가능
    -> 한쪽만 참조하면 단방향
    -> 양쪽이 서로 참조하면 양방향 -> 객체 입장에서는 단방향 총 2개의 단방향

예시 상황
1. 회원(Member) 와 팀(Team) 은 다대일
2. 회원(Member) 와 락커(Locker) 는 일대일

다대일 (N:1)

  • @ManyToOne

  • 가장 많이 사용하는 연관관계

  • 회원 엔티티에 외래키가 존재

  1. 단방향
    -> 회원 엔티티에 팀 객체를 참조하는 형태

  2. 양방향
    -> 외래키가 있는 회원 엔티티가 연관관계의 주인
    -> 팀 엔티티에는 회원을 참조하는 컬렉션 생성

// Member.kt
@ManyToOne
@JoinColumn(name = "TEAM_ID")
var team: Team

// Team.kt
@OneToMany(mappedBy = "team")
val members: MutableList<Member> = arrayListOf()

일대다 (1:N)

  • @OneToMany
  • 일대다 관계보다는 다대일 관계를 주로 사용하게 됨
  • 객체와 테이블의 차이 때문에 반대편 테이블의 외래키를 관리하는 특이한 구조가 되는 모델
    -> 연관관계 관리를 위해 추가로 Update Sql이 실행되는 단점이 생김
  • 따라서 다대일 양방향 매핑을 사용하는 것을 권장
  • @JoinColumn 을 무조건 사용해야 함
    -> 사용안하면 조인 테이블 방식을 사용하게 됨
  1. 단방향
    -> 팀(Team) 엔티티에 회원 객체를 참조하는 컬렉션을 생성
    -> 팀 엔티티에 회원 객체가 추가, 변경이 일어날 때마다 회원 엔티티에 Update SQL이 발생
// Team.kt
@OneToMany
@JoinColumn(name = "TEAM_ID")
val members: MutableList<Member> = arrayListOf()
  1. 양방향
    -> 해당 매핑은 공식적으로 존재하지 않음
    -> 읽기 전용 필드를 사용해서 양방향 처럼 사용하는 방법
    -> @JoinColumn(insertable=false, updatable=false)
// Member.kt
@ManyToOne
@JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
var team: Team

일대일 (1:1)

  • @OneToOne
  • 일대일 관계는 그 반대도 일대일
  • 주 테이블이나 대상 테이블 중 하나를 택해서 외래 키를 선택
  • 외래 키에 데이터베이스 유니크 제약조건 추가
  1. 주 테이블에 외래 키 단방향
  • 다대일(@ManyToOne) 단방향 매핑과 유사
// Member.kt
@OneToOne
@JoinColumn(name = "LOCKER_ID")
var locker: Locker
  1. 주 테이블에 외래 키 양방향
  • 다대일(@ManyToOne) 양방향 매핑처럼 사용
// Locker.kt
@OneToOne(mappedBy = "locker")
var member: Member
  1. 대상 테이블에 외래 키 단방향
  • JPA에서 지원하지 않는다.
  1. 대상 테이블에 외래 키 양방향
  • 주 테이블 외래 키 양방향과 매핑 방법이 같음

일대일 정리
1. 주테이블 외래 키

  • 주 객체가 대상 겍체의 참조를 가지는 것처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾음
  • 장점 : JPA 매핑이 편리, 주 테이블만 조회해도 대상 테이블에 데이터가 있는지 확인 가능
  • 단점 : 값이 없으면 외래 키에 null 허용
  1. 대상 테이블에 외래 키
  • 대상 테이블에 외래 키가 존재
  • 장점 : 주 테이블과 대상 테이블을 일대일에서 일대다 관계로 변경할 때 테이블 구조 유지
  • 단점 : 프로시 기능의 한계로 지연 로딩으로 설정해도 항상 즉시 로딩 됨

다대다 (N:M)

  • @ManyToMany
  • 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없음
  • 연결 테이블을 추가해서 일대다, 다대일 관계로 해결해야 함
    -> 연결 테이블이 단순히 연결만 하고 끝나지 않음
    -> 매핑 정보만 들어가고, 다양한 정보를 추가로 담을 수 없는 문제가 존재
// Member.kt
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT")
val products: MutableList<Product> = arrayListOf()

// Product.kt
@ManyToMany(mappedBy = "products")
val members: MutableList<Member> = arrayListOf()
  • 방법
    -> 연결 테이블용 엔티티를 추가 (연결 테이블을 엔티티로 승격)
    -> @ManyToMany -> @OneToMany, @ManyToOne
// Member.kt
@OneToMany(mappedBy = "member")
val memberProducts: MutableList<MemberProduct> = arrayListOf()

// Product.kt
@OneToMany(mappedBy = "product")
val memberProducts: MutableList<MemberProduct> = arrayListOf()

// MemberProduct.kt
@Entity
class MemberProduct(
    @Id
    @GeneratedValue
    val id: Long? = null,

    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    var member: Member,

    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    var product: Product,

    var count: Int
)

참고 : 인프런 강의[자바 ORM 표준 JPA 프로그래밍 - 기본편]

0개의 댓글