연관관계 매핑 정리(코드 + MySQL)
이 전에 연관관계 이론에 대해서 정리하고
연관관계를 코드에 적용한 후 refactoring을 진행했다.
그리고 그 과정에서 궁금했던 점도 해결했다.
이번엔 마지막으로 한번 더 정리하는 겸으로 글을 작성했고 db에서 fk를 설정하는 방법에 대해 정리했다.
관련 글
Registry와 User 연관관계 매핑
*코드 일부 생략
1. User와 Registry는 1:N 관계다.
User
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
36
37
38
39
40
41
42
43
44
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity // DB 테이블 역할을 한다.
public class User extends Timestamped {
// ID가 자동으로 생성 및 증가
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "user_id")
private Long id;
@Column(nullable = false)
private String username;
@Column(nullable = false)
private String nickname;
@Column(nullable = false)
private String password;
@Column(nullable = true)
private String passwordConfirm;
@Column(nullable = false)
private String email;
@OneToMany(mappedBy = "user")
@JsonIgnore
private List<Registry> registries = new ArrayList<>();
public void addRegistry(Registry registry){
this.registries.add(registry);
if(registry.getUser() != this){ // Registry에서 설정한 User 변수명 : user
registry.addUser(this); // Registry에서 설정한 메소드명
}
}
@Builder
public User(String username, String nickname, String password, String email){
this.username = username;
this.nickname = nickname;
this.password = password;
this.email = email;
}
}
Registry
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
36
37
38
39
40
41
42
43
44
45
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Entity
@ToString
public class Registry extends Timestamped {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
@Column(name = "registry_id")
private Long idx;
// @Column(nullable = false)
// private String nickname;
@Column(nullable = false)
private String title;
@Column(nullable = false)
private String main;
@ManyToOne(fetch = FetchType.LAZY)
@JsonIgnore
@JoinColumn(name = "user_id", nullable = false)
private User user;
@Builder
public Registry(String title, String main, User user) {
//this.nickname = nickname;
this.title = title;
this.main = main;
this.user = user;
}
public void addUser(User user) {
// 기존에 연결된게 있을 경우 초기화
if(this.user != null) {
this.user.getRegistries().remove(this); // User에서 설정한 Registry 변수명 : registries
}
this.user = user;
// 무한 루프 안걸리게 하기
if (!user.getRegistries().contains(this)) {
user.addRegistry(this); // User에서 설정한 메소드명
}
}
}
2. RegistryServiceImpl - user 정보 담기
게시글 작성은 로그인한 자신이기 때문에 front에서 받기 보다 로그인한 user 정보를 받아오기로 했다.
1
2
3
public Registry setUpload(RegistryDto registryDto) throws IOException {
return registryRepository.save(registryDto.toEntity());
}
🔽
1
2
3
4
public Registry postUpload(RegistryDto registryDto, UserDetailsImpl userDetails) throws IOException {
Registry registry = registryDto.toEntity(userDetails.getUser());
return registryRepository.save(registry);
}
3. db에 fk 반영하기
ddl-auto 사용
test용 db 라면 spring.jpa.hibernate.ddl-auto: update
로 입력해서 반영할 수 있다.
ddl-auto란?
JPA에서는 기본적으로 Entity에 테이블을 매핑하면 쿼리를 사용하지 않고 값을 가져올 수 있다.
- create : SessionFactory 시작시 스키마를 삭제하고 다시 생성
- create-drop : SessionFactory 종료 시 스키마를 삭제
- update : SessionFactory 연결된 DB와 비교하여 추가된 항목은 추가하고 만약 같은 변수명이면 오류발생
- validate : SessionFactory 시작시 객체구성과 스키마가 다르다면 예외 발생
- none: 아무것도 안함
*실제 서비스 배포시에는 create, create-drop, update 와 같은 옵션을 사용하면 안되지만
개발 초기 테스트시에는 유용하게 사용할 수 있다.
ddl-auto의 경우 초기 DB 설정 및 간단한 테스트에서만 쓰는게 좋다.
JPA ddl-auto 설정과 더미데이터 생성 방법
쿼리문으로 fk 설정하기
예시로 Registry대신 Comment에 user_id를 fk로 추가해봤다.
comment table에 user table의 pk인 user_id를 fk로 추가하는 쿼리문
1
2
3
4
alter table comment
add
foreign key (user_id)
references user (user_id);
fk로 변경된 것을 확인할 수 있다.