일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
- Oracle 18c 설치
- ORA-12899
- Oracle 테이블 띄어쓰기
- Oracle 사용자명 입력
- oracle
- 비전공자를 위한 데이터베이스 입문
- Oracle 초기 사용자
- 무료 오라클 데이터베이스
- Oracle Express Edition
- Oracle 사용자명
- ora-01722
- 무료 오라클 설치
- Oracle 윈도우 설치
- 오라클 캐릭터셋 조회
- oracle 18c
- 오라클 캐릭터셋 확인
- Oracle 테이블 대소문자
- ORA-00922
- 윈도우 Oracle
- Oracle 18c HR schema
- Orace 18c
- 오라클 캐릭터셋 변경
- 서평단
- Oracle 18c HR
- Today
- Total
The Nirsa Way
[Spring Data JPA] 연관 관계 매핑 (3) : 기타 관계 (@OneToOne, @ManyToMany) 본문
[Spring Data JPA] 연관 관계 매핑 (3) : 기타 관계 (@OneToOne, @ManyToMany)
KoreaNirsa 2025. 7. 17. 11:43
기타 관계 (@OneToOne, @ManyToMany)
ManyToOne, OneToMany 보다 상대적으로 사용 빈도가 낮은 OneToOne, ManyToMany를 기타 관계라고 표현하기도 합니다. 네이밍 그대로 1:1, N:N 관계를 가지는 어노테이션이며 특히 ManyToMany의 경우 중간 매핑 테이블을 따로 분리하는 것이 좀 더 좋은 케이스인 경우가 많으므로 거의 사용되지 않습니다.
1. @OneToOne
한 명의 학생(student)은 하나의 사물함(rocker)만 사용해야하는 경우와 같이 1:1로 매핑되어야 하는 상황에서 사용되는 어노테이션 입니다. 단방향을 기준으로 작성된 엔티티는 다음과 같습니다.
@Entity
public class Student {
@Id @GeneratedValue
private Long id;
private String name;
@OneToOne
@JoinColumn(name = "locker_id")
private Locker locker;
}
@Entity
public class Locker {
@Id @GeneratedValue
private Long id;
private String location;
}
위의 엔티티를 기준으로 테이블을 생성하면 아래와 같은 DDL이 완성되는데, 엔티티에서는 locker_id를 기준으로 1:1 매핑인 상태이므로 SQL의 제약조건에도 UNIQUE를 주어야 합니다.
만약, UNIQUE가 없다면 중복된 데이터가 삽입이 가능해지고 이로 인해 1:N 관계가 될 가능성이 있기 때문에 UNIQUE를 주어 1:1 관계를 보장 받아야 합니다.
CREATE TABLE locker (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
location VARCHAR(255)
);
CREATE TABLE student (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255),
locker_id BIGINT UNIQUE,
CONSTRAINT fk_student_locker FOREIGN KEY (locker_id) REFERENCES locker(id)
);
2. @ManyToMany
N:N 관계의 경우 거의 사용되지 않는 케이스이며 이러한 관계를 가질 경우 중간 테이블 확장이 불가능하여 다시 설계 및 구조를 변경해야 하는 상황이 발생할 수 있습니다. ManyToMany는 간단히 엔티티와 DDL 예시만 살펴보고 넘어가도록 하겠습니다.
이번에는 DDL을 먼저 살펴볼텐데, member_role이라는 테이블이 각각 member와 role을 참조하는 식별 관계인 케이스 입니다.
CREATE TABLE member (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(255)
);
CREATE TABLE role (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
role_name VARCHAR(255)
);
CREATE TABLE member_role (
member_id BIGINT,
role_id BIGINT,
PRIMARY KEY (member_id, role_id),
FOREIGN KEY (member_id) REFERENCES member(id),
FOREIGN KEY (role_id) REFERENCES role(id)
);
엔티티는 아래와 같이 진행되며 ManyToMany 어노테이션을 사용하여 N:N 관계임을 정의하고, N:N을 표현하기 위한 중간 조인 테이블(member_role)을 설정합니다. 이후 각각 JoinColumn을 사용하여 외래키를 지정해주는 방식입니다.
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String username;
@ManyToMany
@JoinTable(
name = "member_role",
joinColumns = @JoinColumn(name = "member_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private List<Role> roles = new ArrayList<>();
}
@Entity
public class Role {
@Id @GeneratedValue
private Long id;
private String roleName;
}
사실, 설계할 때 이러한 구조보다는 아래와 같이 N:1 관계를 지정해주는 중간 엔티티(MemberRole)을 사용하는 방식이 권장됩니다.
@Entity
public class MemberRole {
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
@ManyToOne
@JoinColumn(name = "role_id")
private Role role;
}
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String username;
@OneToMany(mappedBy = "member")
private List<MemberRole> memberRoles = new ArrayList<>();
}
@Entity
public class Role {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "role")
private List<MemberRole> memberRoles = new ArrayList<>();
}