JPA02. 관계
1:N 관계
@ManyToOne 단방향
1
2
3
4
5
6
7
8
9
10
11
12
@Getter @Setter
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
@Column(nullable=false, unique=true)
private String username;
private String password;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@Getter @Setter
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne // <- FK
@JoinColumn(name="owner_id")
private Account owner;
}
Study에서는 Account를 참조할 수 있지만, Account에서는 Study를 알 수 없음.
@ManyToOne
: Study에 Account 관계를 맺어줬음. 단방향임.
@JoinColumn
: 생략 가능함. ‘필드명_참조하는필드명’ 으로 생성됨. 위의 경우 생략하면 컬럼 이름은 owner_id
깨알팁) @ManyToOne
와 @OneToMany
가 헷갈린다면..
끝쪽을 보세요! 끝이 One으로 끝나면 단일, Many로 끝나면 컬렉션인 레퍼런스를 쓴다고 생각!
현재 Reference가 Collection이 아니라 Account니까 One으로 끝나는거다!
결과
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CREATE TABLE account (
id int8 not null,
password varchar(255),
username varchar(255) not null,
primary key (id)
)
CREATE TABLE study (
id int8 not null,
name varchar(255),
owner_id int8,
primary key (id)
)
ALTER TABLE IF EXISTS account
ADD CNSTRAINT UK_gex1lmaqpg0ir5g1f5eftyaa1 UNIQUE (username)
ALTER TABLE IF EXISTS study
ADD CONSTRAINT FK210g5r7wftvloq2ics531e6e4
FOREIGN KEY (owner_id) REFERENCES account
Study는 onwer의 PK인 ower_id를 FK로 가지고 있음.
@OneToMany 단방향
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Getter @Setter
@Entity
public class Account {
@Id @GeneratedValue
private Long id;
@Column(nullable=false, unique=true)
private String username;
private String password;
@OneToMany
private Set<Study> studies;
}
1
2
3
4
5
6
7
8
9
@Getter @Setter
@Entity
public class Study {
@Id @GeneratedValue
private Long id;
private String name;
}
@OneToMany
: 이번에는 Account에서 Study 관계를 맺어줬음. 단방향임.
조인테이블이 만들어짐.
결과
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
32
33
34
35
create table account (
id int8 not null,
password varchar(255),
username varchar(255) not null,
primary key (id)
)
create table account_studies (
account_id int8 not null,
studies_id int8 not null,
primary key (account_id, studies_id)
)
create table study (
id int8 not null,
name varchar(255),
primary key (id)
)
alter table if exists account
add constraint UK_gex1lmaqpg0ir5g1f5eftyaa1
unique (username)
alter table if exists account_studies
add constraint UK_tevcop76y9etp9vx5vce7gns6
unique (studies_id)
alter table if exists account_studies
add constraint FKem9ae62rreqwn7sv2efcphluk
foreign key (studies_id) references study
alter table if exists account_studies
add constraint FK4h3r1x3qcsugrps8vc6dgnn25
foreign key (account_id) references account
이건 바꿀 수있음. 위는 빙산의 일각에 불과
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Account {
// ...
// 어떤 한 유저에 스터디를 추가할 때, 해당 스터디에서의 정보도 함께 변동되어야 함
public void addStudy(Study study) {
this.getStudies().add(study);
study.setOwner(this);
}
public void removeStudy(Study study) {
this.getStudies().remove(study);
study.setOwner(null);
}
}
@OneToMany, @ManyToOne 양방향
RDB에는 FK 한개로 양방향 관계를 가짐.
그런데 객체에서의 양방향은 각 클래스에서 참조를 하게 됨.
이 때 생각해야할 것이 있음. 한쪽에 업데이트를 하면 반대쪽도 업데이트 되야 한다는 것임.
=> 그럼 둘중에 한군데를 주인으로 만들고, 주인이 아닌 쪽은 읽기만 가능하도록 하자!
주인이 아닌 쪽은 읽기만 가능. -> DB에 영향을 주지 않음. 양방향은 단순히 조회를 편하게 하기 위한 부가기능!? 나중에 DDL보면 @ManyToOne 단방향이랑 같을거임.
누구를 주인으로 할까? FK 가지고 있는 쪽을 관계의 주인으로 하자. 이렇게 안하면 어떤 테이블 수정헀는데 다른테이블에 쿼리가 날라가면서 멘붕에 빠질 수 있음.
주인이 아닌 쪽에서는 mappedBy 설정을 해줘야 함. 안하면 양방향이 아닌, 두개의 단방향 관계가 되서 꼬여버림.
mappedBy는 양방향 관계일 때 사용. 매핑된 엔터티의 필드명을 적으면됨.
주인이 아닌쪽에서 추가해버리면 DB에 반영 안됨.
1
2
3
4
5
6
7
@Entity
public class Account {
// ...
@OneToMany(mappedBy = "owner")
private Set<Study> studies = new HashSet<>();
}
1
2
3
4
5
6
7
public class Study {
// ...
@ManyToOne
@JoinColumn(name="owner_id")
private Account owner;
}
결과
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
CREATE TABLE account (
id int8 not null,
password varchar(255),
username varchar(255) not null,
primary key (id)
)
CREATE TABLE study (
id int8 not null,
name varchar(255),
owner_id int8,
primary key (id)
)
ALTER TABLE IF EXISTS account
ADD CNSTRAINT UK_gex1lmaqpg0ir5g1f5eftyaa1 UNIQUE (username)
ALTER TABLE IF EXISTS study
ADD CONSTRAINT FK210g5r7wftvloq2ics531e6e4
FOREIGN KEY (owner_id) REFERENCES account
-> @ManyToOne 단방향이랑 스키마가 똑같다!!
김영한님 팁!
- 설계할 때는 무조건 단방향으로 설계! (양방향은 좋은것이 아님. 순환참조라는게..)
- 개발 도중에 양방향이 필요하다고 생각할 경우 추가. (DB에 영향 안주니까 나중에 추가되도 괜찮음)
- 양방향은 조회하기 편하려고 부가기능이 들어간 것!
- 아리까리하면 JPA책 볼 것ㅋㅋ