📖
Kyu9's Repo
  • Library of mameil
  • 이슈 경험
    • 20230220_트랜잭션
    • 20230306_캐싱이슈
    • 20230722_테스트코드에서 @Transactional
    • 20230807_deadlock
  • 인턴 스터디
    • Gradle
    • Stream, Optional, 람다식
    • JVM의 메모리 구조, Garbage Collector
    • RESTful API
    • Microservice Architecture
    • HTTP
    • 웹서버란 무엇인가
    • Git Branch
    • TDD
    • Redis을 이용한 캐시
    • Thymeleaf
    • 정리가 필요한 자료들
    • SpringBoot Management
    • 테스크 코드 분할
  • 동아리 스터디
    • 기본 SQL 공부
      • SQL의 기본 개념
      • SELECT 문장을 이용하여 원하는 데이터 출력하기
        • 집합 연산자 사용하기
        • where절에 비교 연산자를 사용해보기
        • SELECT_EX
        • 산술 연산자 사용해보기
      • 단일 행 함수 사용
        • lower/upper 함수 사용하기
        • length함수 사용하기
        • concat함수 사용
        • substr/mid/substring 함수 사용
        • instr함수 사용하기
        • lpad/rpad 함수 사용하기
        • trim/ltrim/rtrim 함수 사용하기
        • replace 함수 사용하기
        • round 함수 사용하기
        • truncate 함수 사용하기
        • mod함수 사용하기
        • ceil함수 사용하기
        • floor함수 사용하기
        • power 함수 사용하기
        • Date fn(날짜 함수)
        • 형 변환 함수
        • 일반함수란
    • a-ha 실습
    • 혼자서 만들어본 게시판
    • AWS 강의
  • 학교 나머지 공부 자료
    • 웹프레임워크(Spring)
      • Spring이란?
      • Webframework1-1
      • Webframework1-2
      • SpringBoot의 특징
      • SpringBoot 생성 방법
      • Spring Data JPA
      • SpringBoot Security
      • SpringBoot HATEOAS
  • 공부 자료들
  • WS 온라인 자바 스터디
    • Week1(JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.)
    • Week2(자바 데이터 타입, 변수 그리고 배열)
    • Week3(연산자)
    • Week4(제어문)
    • Week5(클래스)
    • Week6(상속)
    • Week7(패키지)
    • Week8(인터페이스)
    • Week9(예외처리)
    • Week10(멀티쓰레드 프로그래밍)
    • Week11(Enum)
    • Week12(Annotation)
    • Week13(I/O)
    • Week14(Generic)
    • Week15(람다식)
  • 백준문제
    • 입출력과 사칙연산
      • We love kriii(10718)
      • 고양이(10171)
      • 개(10172)
      • A+B(1000)
      • A-B(1001)
      • AxB(10998)
      • A/B(1008)
      • 사칙연산(10869)
      • 나머지(10430)
      • 곱셈(2588)
    • for문
      • 구구단(2739)
      • A+B - 3(10950)
      • 합(8393)
      • 빠른 A+B(15552)
      • N 찍기(2741)
      • 기찍 N(2742)
      • A+B - 7(11021)
      • A+B - 8(11022)
      • 별 찍기 - 1(2438)
      • 별 찍기 - 2(2439)
      • X보다 작은 수(10871)
    • if문
      • 두 수 비교하기(1330)
      • 시험 성적(9498)
      • 윤년(2753)
      • 사분면 고르기(14681)
      • 알람 시계(2884)
      • 오븐 시계(2525)
      • 주사위 세개(2480)
      • 영수증(25304)
    • While문
      • A+B - 5(10952)
      • A+B - 4(10951)
      • 더하기 사이클(1110)
    • 1차원 배열
      • 최소, 최대(10818)
      • 최댓값(2562)
      • 숫자의 개수(2577)
      • 나머지(3052)
      • 평균(1546)
      • OX퀴즈(8958)
      • 평균은 넘겠지(4344)
    • 함수
      • 정수N개의 합(15596)
      • 셀프 넘버(4673)
      • 한수(1065)
    • 문자열
      • 아스키코드(11654)
      • 숫자의 합(11720)
      • 알파벳 찾기(10809)
      • 문자열 반복(2675)
      • 단어 공부(1157)
      • 단어의 개수(1152)
      • 상수(2908)
      • 다이얼(5622)
      • 크로아티아 알파벳(2941)
      • 그룹 단어 체커(1316)
    • 기본수학-1
      • 손익분기점(1712)
      • 벌집(2292)
      • 분수찾기(1193)
      • 달팽이는 올라가고 싶다(2869)
      • ACM 호텔(10250)
      • 부녀회장이 될테야(2775)
      • 설탕 배달(2839)
      • 큰 수 A+B(10757)
      • Fly me to the Alpha Centauri(1011)
    • 기본수학-2
      • 소수 찾기(1978)
      • 소수(2581)
      • 소인수분해(11653)
      • 소수 구하기(1929)
      • 베르트와 공존(4948)
    • 재귀
      • 하노이 탑 이동 순서(11729)
      • 피보나치 수 5(10870)
      • 별 찍기(2447)
    • 브루트 포스
      • 블랙잭(2798)
      • 분해합(2231)
      • 덩치(7568)
      • 체스판 다시 칠하기(1018)
      • 영화감독 슘(1436)
    • 집합과 맵
      • 숫자 카드(10815)
      • 문자열 집합(14425)
      • 숫자 카드2(10816)
      • 듣보잡(1764)
      • 대칭 차집합(1269)
      • 서로 다른 부분 문자열 갯수(11478)
    • 정렬
      • 수 정렬하기(2750)
      • 수 정렬하기 2(2751)
      • 수 정렬하기 3(10989)
      • 통계학(2108)
      • 소트인사이드(1427)
      • 좌표 정렬하기(11650)
      • 좌표 정렬하기2(11651)
      • 단어 정렬(1181)
      • 나이순 정렬(10814)
      • 커트라인(25305)
      • 좌표압축(18870)
    • 백트래킹
      • N과 M - 1(15649)
      • N과 M - 2(15650)
      • N과 M - 3(15651)
      • N과 M - 4(15652)
      • N-Queen(9663)
      • 스도쿠(2580)
      • 연산자 끼워넣기(14888)
      • 스타트와 링크(14889)
    • 이분 탐색
      • 수 찾기(1920)
    • 동적계획법
      • 피보나치 함수(1003)
      • 신나는 함수 실행(9184)
      • 01타일(1904)
      • 파도반 수열(9461)
      • RGB거리(1149)
      • 정수 삼각형(1932)
      • 계단 오르기(2579)
      • 1로 만들기(1463)
      • 쉬운 계단 수(10844)
      • 포도주 시식(2156)
      • 가장 긴 증가하는 부분 수열(11053)
      • 가장 긴 바이토닉 부분 수열(11504)
      • 전깃줄(2565)
      • LCS(9251)
      • 연속합(1912)
      • 평범한 배낭(12865)
      • 더하기(9095)
    • DFS와 BFS
      • 미로탐색(2178)
      • 바이러스(2606)
      • DFS와 BFS(1260)
      • 단지번호붙이기(2667)
      • 전쟁 - 전투(1303)
      • 숨바꼭질(1697)
      • 데스 나이트(16948)
      • 나이트의 이동(7562)
      • 녹색 옷 입은 애가 젤다지?(4485)
      • 음식물 피하기(1743)
      • A->B (16953)
      • 숨바꼭질 3(13549)
      • 숨바꼭질 2(12851)
    • 구현
      • 치즈(2636)
  • 프로그래머스 문제
    • SQL
      • Animal Table - Oracle
      • Animal Table - MySQL
      • Animal Table2 - Oracle
      • Animal Table 3,4 - Oracle
    • Lv1
      • 두 개 뽑아서 더하기
      • 제일 작은 수 제거하기
      • 문자열 내 p와 y의 개수
      • 예산
      • 자릿수 더하기
      • 두 정수 사이의 합
      • 같은 숫자는 싫어
      • 가운데 글자 가져오기
      • 수박수박수박수박수박수?
      • 나누어 떨어지는 숫자 배열
      • 2016년
      • 폰캣몬
      • 서울에서 김서방 찾기
      • 문자열을 정수로 바꾸기
      • 소수 만들기
      • 문자열 다루기 기본
      • 소수 찾기(에라토스테네스의 체)
      • 숫자 문자열과 영단어
      • 이상한 문자 만들기
      • 없는 숫자 더하기
      • 문자열 내림차순으로 배치하기
      • 문자열 내 마음대로 정렬하기
      • 약수의 개수와 덧셈
      • 콜라츠 추측
      • 자연수 뒤집어 배열로 만들기
      • 신규 아이디 추천
      • 비밀지도
      • 크레인 인형뽑기 게임
      • 실패율
      • 로또의 최고 순위와 최저 순위
      • 키패드 누르기
      • 정수 내림차순으로 배치하기
    • Lv2
      • 행렬의 곱셈
      • 영어 끝말잇기
      • 영어 끝말잇기
      • N개의 최소 공배수
      • 피보나치 수
      • 124 나라의 숫자
      • 짝지어 제거하기
      • 프린터
      • 다음 큰 숫자
      • 최댓값과 최솟값
      • 최소값 만들기
      • 숫자의 표현
      • JadenCase 문자열 만들기
      • 오픈채팅방
      • 영어 끝말잇기
      • 멀쩡한 사각형
      • 올바른 괄호
      • 위장
      • 기능개발
      • 더 맵게
      • 스킬트리
    • 완전탐색
      • 모의고사(Lv1)
      • 카펫(Lv2)
      • 소수 찾기(Lv2)
    • 정렬(Sorting)
      • K번째 수(Lv1)
      • 가장 큰 수(Lv2)
      • H-Index(Lv2)
    • 해시(Hash)
      • 완주하지 못한 선수(Lv1)
      • 전화번호 목록(Lv2)
    • 탐욕법(Greedy)
      • 체육복(Lv1)
      • 큰 수 만들기(Lv2)
      • 구명보트(Lv2)
    • 동적계획법(DP)
      • 정수 삼각형(Lv3)
    • 깊이/너비 우선 탐색(DFS/BFS)
      • 타겟 넘버(Lv2)
      • 네트워크(Lv3)
      • 단어 변환(Lv3)
  • 스프링부트 책
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
  • JPA 책
    • 프로젝트 세팅 및 기본설정
    • 영속성 관리 개념
    • 엔티티 매핑
      • 실습 예제
    • 연관관계 매핑 기초
      • 실습 예제
    • 다양한 연관관계 매핑
      • 다대일, 일대다 관계
      • 일대일, 다대다 관계
      • 실습 예제
    • 고급 매핑
      • 상속 관계 매핑
      • @MappedSuperclass
      • 복합 키와 식별 관계 매핑
      • 조인 테이블
    • 프록시와 연관관계 관리
      • 프록시
      • 즉시 로딩과 지연 로딩
      • 영속성 전이, 고아 객체
    • 값 타입
      • 임베디드 타입
      • 값 타입과 불변 객체
      • 값 타입의 비교, 컬렉션
    • 객체지향 쿼리 언어
      • JPQL part1
      • JPQL part2
      • JPQL part3
      • QueryDSL
      • NativeSQL
      • 객체지향 쿼리 심화
    • 응용 애플리케이션
      • 엔티티 설정
    • 스프링 데이터 JPA
      • 공통 인터페이스
  • Kotlin In Action
    • 코틀린의 특징
    • 코틀린의 기초
    • 함수 정의와 호출
    • 클래스, 객체, 인터페이스
    • 람다 방식
    • 코틀린 타입 시스템
    • 연산자 오버로딩과 기타 관례
    • 고차함수
    • 제네릭스
    • 애노테이션과 리플렉션
    • 코루틴
  • Oracle
    • Oracle 기본
    • Oracle 심화
  • SQL_연습
    • Revising the Select Query
    • Basic Select
    • Advanced Select
    • Basic Select 2
  • SQL 첫걸음(책)
    • Day 1
    • Day 2
    • Day 3
    • Day 4
    • Day 5
    • Day 6
    • Day 7
    • Day 8
    • Day 9
    • Day 10
    • Day 11
    • Day 12
    • Day 13
    • Day 14
    • Day 15
    • Day 16
    • Day 17
    • Day 18
    • Day 19
    • Day 20
    • Day 21
    • Day 22
    • Day 23
    • Day 24
    • Day 25
    • Day 26
    • Day 27
    • Day 28
    • Day 29
    • Day 30
  • 더 자바 코드를 조작하는 다양한 방법
    • JVM 이해하기
    • 바이트코드 조작
    • 리플렉션
    • 다이나믹 프록시
    • 애노테이션 프로세서
  • 더 자바, 애플리케이션을 테스트하는 다양한 방법
    • JUnit5
    • Mockito
    • 도커와 테스트
    • 성능, 운영이슈, 아키텍처 테스트
  • 이펙티브 자바
    • item1 - 생성자 대신 정적 팩토리 메소드를 고려하라
    • item2 - 생성자에 매개변수가 많다면 빌더를 고려하라
    • item3 - 생성자나 열거타입으로 싱글턴임을 보증하라
    • item4 - 인스턴스화를 막기 위해선 private 생성자를 사용하라
    • item5 - 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라
    • item6 - 불필요한 객체 생성을 피하라
    • item7 - 다 쓴 객체 참조를 해제하라
    • item8 - finalizer와 cleaner 사용을 피하라
    • item9 - try-finally 보다 try-with-resources을 사용하라
    • item10 - equals는 일반 규약을 지켜 재정의하라
    • item11 - equals을 재정의하려면 hashCode도 재정의하라
    • item12 - toString을 항상 재정의하라
    • item13 - clone 재정의는 주의해서 진행하라
    • item14 - Comparable을 구현할지 고민하라
  • Elastic Search
    • 강의 Summary
    • Elastic Summary 개념 정리
    • Elastic Summary 적용 정리
  • 토비의 스프링 강의
    • 스프링부트 살펴보기
    • 독립 실행형 서블릿 애플리케이션
  • k8s
    • minikube 설치
    • jenkins 추가
  • Article
    • Choosing the Right MessageBroker
Powered by GitBook
On this page
  • 일대일, 다대다 관계
  • 일대일
  • 다대다

Was this helpful?

  1. JPA 책
  2. 다양한 연관관계 매핑

일대일, 다대다 관계

일대일, 다대다 관계

일대일

1:1의 관계는 양쪽이 서로 하나의 관계만을 가지게 된다. 특징으로는

  • 일대일 관계는 그 반대도 일대일 관계이다

  • 테이블 관계에서 일대다, 다대일은 항상 다쪽에 외래키를 갖게 되지만, 일대일은 양 테이블 중 어디에든 외래키가 들어가던 상관 없다

외래키가 어디에 들어가든 상관 없기 때문에 어느 특정한 테이블을 정해줘야 들어갈 수 있게 되는데, 어떻게 선택할 것인가? 그러면 관계의 주가 되는 테이블에 있는 경우와 그 반대의 경우가 있겠다

주 객체에 외래키가 있을 때는 기존에 객체 지향에서 사용하는 것 처럼 외래키를 사용해서 다른 객체를 참조해서 사용하고 있기 때문에 익숙하다고 볼 수 있다. 이것의 장점으로는 주 테이블만 확인해도 어떤 테이블과 관계를 맺고 있는지 확인할 수 있다는 점이 장점이다.

그럼 반대로 주가 아닌 객체에 외래키가 있는 경우는 옛날의 데이터베이스 방식이라고 볼 수 있다. 그렇다고 절 대 나쁜 방법은 아니라고 한다. 이 방식을 사용한 경우에는 어렵지 않게 일대일 방식에서 일대다 방식으로 변경할 수 있다는 것이 장점이다.

이번 예시는 기존의 Member와 각 member에게 할당되어 있는 하나의 Locker 테이블로 진행된다.

주 객체에 외래키가 있는 경우의 단방향

Member가 주 객체가 되기 때문에 Member에서 Locker에 대한 객체를 가지고 있어줘야 한다.

Memeber

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String username;
    
    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
    private Team team;
}

Locker

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Data
public class Locker {
    @Id
    @GeneratedValue
    @Column(name = "LOCKER_ID")
    private Long id;
    
    private String name;
}

이렇게 Member에서 @OneToOne으로 일대일인 것을 보여주고, 기존의 방식과 같게 @JoinColumn(name=키)이렇게 외래키에 대한 정의를 해주었다.

주 객체에 외래키가 있는 경우 양방향

단방향에서는 주 객체에서만 @OneToOne을 통해서 표시를 해주었지만 양방향인 경우에는 주가 아닌 대상 객체에서도 처리를 해줘야겠지..?

Member - 이건 위와 같겠고

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String username;
    
    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
    private Team team;
}

Locker

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.*;

@Entity
@Data
public class Locker {
    @Id
    @GeneratedValue
    @Column(name = "LOCKER_ID")
    private Long id;

    private String name;
    
    @OneToOne(mappedBy = "MEMBER_ID")
    private Member member;
}

이제는 반대쪽에서도 해당 정보를 가지고 있어야 하기 때문에 @OneToOne을 통해서 Member의 ID로 매핑되었다는 정보를 적어주어야 한다.

다대다

기본적으로 관계형 데이터 베이스에서는 테이블 2개를 가지고 다대다 관계를 표현할 수 없다. 보통은 일대다, 다대일 관계로 풀어내서 다대다 관계를 표현하곤 하는데, 이러한 방법은 2개의 테이블 사이에 연결 테이블을 하나 더 추가하는 방식을 통해서 구현해 낸다.

하지만..! 객체 관계에서는 다대다의 관계를 표현할 수 있다는 점이 있다. 2개의 객체 서로 컬렉션을 사용해서 서로의 객체를 참조하면 어렵지 않게 구현할 수 있다는 점이 있다.

이번의 예시로는 Member와 Product로 구현

다대다 단방향

Product

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
@Data
public class Product {
    @Id
    @GeneratedValue
    private String Id;

    private String name;
}

Member

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String username;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
    private Team team;

    @ManyToMany
    @JoinTable(
            name = "MEMBER_PRODUCT",
            joinColumns = @JoinColumn(name = "MEMBER_ID"),
            inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID")
    )
    private List<Product> products = new ArrayList<>();
}

음.. 뭔가 많아 졌네...

Memeber 엔티티와 Product 엔티티를 매핑했는데, 방식으로는 @ManyToMany와 @JoinTable을 사용해서 진행했다. 이런 방식을 사용하게 되면 따로 Member_Product엔티티가 없어도 매핑을 할 수 있다는 점!

@JoinTable의 속성

  • name : 연결 테이블을 지정한다.

    • 위의 같은 경우에는 Member측에서는 MemberId를, Product측에서는 ProductId를 내새웠기 때문에 Member_Product 엔티티의 구성은 위의 2 키를 PK, FK로 들고 있는 상황이 된다.

  • joinColumns : 현재 방향인 Member와 매핑할 조인 컬럼을 적어줌

  • inverseColumns : 반대 방향인 Product와 매핑할 조인 컬럼을 적어줌

신기하게도 이렇게 엔티티를 구성하고 저장하는 과정에서 product와 member를 세팅하고 persist를 통해 저장을 해준다면 신기하게도 연결 테이블에도 값이 저장된다.

조회할때도 자동으로 Member_Product테이블을 통해서 조회를 해준다..! 완전편리

다대다 양방향

기존에 일대일 단방향에서 양방향으로 바뀔때랑 같이 Product에도 Member에 대한(주인)에 대한 정보를 입력해주면 된다 → mappedBy가 없는 곳이 주인이다!!

Member

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String username;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;

    @ManyToOne
    @JoinColumn(name = "TEAM_ID", insertable = false, updatable = false)
    private Team team;

    @ManyToMany
    @JoinTable(
            name = "MEMBER_PRODUCT",
            joinColumns = @JoinColumn(name = "MEMBER_ID"),
            inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID")
    )
    private List<Product> products = new ArrayList<>();
}

Product

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.ManyToMany;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
public class Product {
    @Id
    @GeneratedValue
    private String Id;

    private String name;
    
    @ManyToMany(mappedBy = "products")
    private List<Member> members = new ArrayList<>();
}

기본적인 ManyToMany 관계는 이러하다.

다대다의 한계점, 해결방안

이렇게만 되면 정말 행복하겠지만

한계점이 있다... 위와 같은 예시에서 Member와 Product의 매핑 사이에 날짜와 같은 새로운 컬럼이 추가되야 하는 경우가 있는데, 새로운 컬럼이 추가되게 되면 @ManyToMany로는 다대다 관계를 표현할 수 없고, 연결 엔티티를 따로 만들고 그 컬럼들에 기존의 매핑해야할 두 컬럼을 매핑해서 일대다, 다대일 관계로 풀어내야 한다..!

이번에는 그 연결 엔티티를 MemberProduct로 풀어내고자 한다.

그럼 일단 기존의 ManyToMany를 OneToMany, ManyToOne으로 해체를 시켜줘야한다.

일단 Member와 MemberProduct는 양방향 관계로 만들었고, 외래 키는 MemberProduct에서 가지고 있기 때문에 주 객체는 MemberProduct가 되고 Member에는 mappedBy로 주가 아님을 표현

Member

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@Entity
@Data
public class Member {
    @Id
    @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String username;
    
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts;
}

Product

여기에는 연관관계를 만들지 않았다.

MemberProduct

package com.example.jpa_project.ch06Example;

import javax.persistence.*;
import java.time.LocalDate;

@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {
    @Id
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @Id
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;

    private LocalDate createdAt;
}

MemberProductId

package com.example.jpa_project.ch06Example;

import java.io.Serializable;
import java.util.Objects;

public class MemberProductId implements Serializable {
    //각 MemberProduct의 member, product객체에 연결
    private String member;
    private String product;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MemberProductId that = (MemberProductId) o;
        return Objects.equals(member, that.member) && Objects.equals(product, that.product);
    }

    @Override
    public int hashCode() {
        return Objects.hash(member, product);
    }
}package com.example.jpa_project.ch06Example;

import javax.persistence.*;
import java.time.LocalDate;

@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {
    @Id
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @Id
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;

    private LocalDate createdAt;
}package com.example.jpa_project.ch06Example;

import javax.persistence.*;
import java.time.LocalDate;

@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {
    @Id
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @Id
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;

    private LocalDate createdAt;
}

MemberProduct에서 다 같은데 @IdClass가 눈에 띈다. 이 것을 사용해서 복합 기본 키를 매핑한다.

복합 기본 키

MemberProduct의 기본 키는 MemberId + ProductId로 구성되어 있고 이런 것을 보고 복합 기본 키라고 한다.

JPA에서 복합 기본 키를 사용하기 위해서는 별도의 식별자 클래스를 만들어야 하며, 그 별도의 식별자 클래스를 @IdClass를 통해서 지정해줘야한다는 특이점이 있다.

식별자 클래스의 특징

  • 복합 기본 키는 별도의 식별자 클래스를 만들어야 한다.

  • Serializable을 구현해야 한다.

  • equals와 hashCode의 메소드를 구현해야 한다(그냥 ide에서 제공해주는 걸로 추가하자)

  • 기본 생성자가 있어야한다.

  • 식별자 클래스의 접근 타입은 public

  • @IdClass말고 @EmbeddedId를 사용하는 방법도 있음

식별 관계

MemberProduct의 기본 키는 Member, Product의 기본 키를 받아서 자신의 기본 키로 사용하는데, 이렇게 부모 테이블의 기본 키를 받아서 자신의 기본키, 외래키로 사용하는 관계를 보고 식별 관계 라고 부른다.

이렇게 귀찮은 복합 키를 사용하지 않고도 간단하게 사용하는 방법도 있다는 점!

다대다 새로운 기본 키 사용

가장 추천하는 키 생성 전략은 그냥 DB에서 자동으로 생성해주는 대리 키를 Long값으로 사용하는 것이다..!

여기서 가장 큰 장점은 반 영구적으로 사용이 가능하며, ORM 매핑 시에 복합 키를 만들지 않아도 된다는 점!!

그럼 위에서 만들었던 MemberProduct 엔티티의 이름을 Orders로 변경해보자

Orders

package com.example.jpa_project.ch06Example;

import lombok.Data;

import javax.persistence.*;
import java.time.LocalDate;

@Entity
@Data
public class Orders {
    @Id
    @GeneratedValue
    @Column(name = "ORDER_ID")
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
    
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
    
    private LocalDate createdAt;
}

이렇게 굳이 키를 받아서 조합해서 사용하는 것 보다는 그냥 새로운 기본 키를 만들어서 사용하는 것이 몇 배는 더 간결해진 것 같다.

다대다 → 일대다 + 다대일 : 식별자의 구성

식별 관계 : 부모 테이블에서 받아온 식별자를 기본 키 + 외래 키로 사용

비식별 관계 : 받아온 식별자를 외래 키로만 사용하고 새로운 식별자를 추가

객체 지향적인 관점에서는 비식별 관계가 더욱 편리하게 ORM매핑을 사용할 수 있다는 점!

Previous다대일, 일대다 관계Next실습 예제

Last updated 3 years ago

Was this helpful?