개발환경
Springboot 2.7.0
SpringDataJPA
Lombok
MySQL
문제사항
JPA 공부하고 기존 진행했던 간단한 게시판 프로젝트에 JPA를 적용 중 이미지 파일 처리에서 문제가 발생.
//imageBoard Entity(사진 게시판)
@Entity
@Data
@Builder
public class ImageBoard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long imageNo;
@NonNull
private String imageTitle;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId")
@ToString.Exclude
private Member member;
private Date imageDate;
private String imageContent;
@OneToMany(mappedBy = "imageBoard", fetch = FetchType.LAZY)
@ToString.Exclude
private final Set<comment> comments = new HashSet<>();
@OneToMany(mappedBy = "imageBoard", fetch = FetchType.LAZY)
@ToString.Exclude
private final Set<ImageData> imageDataSet = new HashSet<>();
}
// ImageData Entity(이미지 파일)
@Entity
@Data
@Builder
public class ImageData {
@Id
private String imageName;
@ManyToOne
@JoinColumn(name = "imageNo")
@ToString.Exclude
private ImageBoard imageBoard;
@NonNull
private String oldName;
private int imageStep;
}
이렇게 두가지 엔티티가 이미지 게시판을 구성하게 된다.
그럼 insert를 한다고 했을 때 ImageBoard 엔티티를 먼저 저장해주고 ImageData 엔티티를 저장해줘야 한다.
ImageBoard 테이블에 imageNo가 존재해야 ImageData에 해당 게시글의 파일 정보를 저장할 수 있으니까.
최근에 'Entity는 Setter를 최대한 사용하지 않는것이 좋다. 꼭 Entity에 set을 해줘야 한다면 builder를 사용하는것이 좋다.' 라는 포스팅을 봤다.
봤으면 적용해야되니 builder를 통해 처리하고자 했다.
//처리코드
// imageBoardInsert 메소드
....
ImageBoard imageBoard = ImageBoard.builder()
.member(principalService.checkPrincipal(principal)
.imageTitle(request.getParameter("imageTitle"))
.imageContent(request.getParameter("imageContent"))
.imageDate(Date.valueOf(LocalDate.now()))
.build();
imageBoardRepository.save(imageBoard);
...
//파일 처리 메소드(imageBoardInsert 메소드에서 호출)
ImageBoard imageBoard = new ImageBoard();
imageBoard.setImageNo(imageNo);
ImageData imageData = ImageData.builder()
.imageboard(imageBoard)
.imageName(saveName)
.oldName(originalName)
.imageStep(step)
.build();
imageDataRepository.save(imageData);
....
이렇게 작성했더니 바로 오류가 발생했다.
오류는 imageTitle은 NonNull이기 때문에 null이 들어가면 안된다는것.
처음한 생각으로는 연관관계 매핑을 해놨고 imageNo만 있으면 되겠지? 해서 setImageNo를 했고
안되길래 builder로 imageNo만 넣어서 빌드를 한 다음에 넣어봤는데 그것도 안되고...
@NonNull 어노테이션만 지우면 바로 해결되는 문제이긴 했지만 만약 이걸 사용해야 하는 환경에서 이런 문제에 또 부딪히게 되면 그때가서 또 시간 써야 될것 같아서 방법을 찾아봄.
간단하게 설명하자면 연관관계 매핑이 되어있으면 One 에 해당하는 Entity에 Many 에 해당하는 Entity를 담아 한번에 save가 가능하다.
처리는 아래처럼 하면 된다.
// ImageBoard Entity
@Entity
@Data
@Builder
public class ImageBoard {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long imageNo;
@NonNull
private String imageTitle;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "userId")
@ToString.Exclude
private Member member;
private Date imageDate;
private String imageContent;
@OneToMany(mappedBy = "imageBoard", fetch = FetchType.LAZY)
@ToString.Exclude
private final Set<Comment> comments = new HashSet<>();
// cascade = CascadeType.ALL 추가
@OneToMany(mappedBy = "imageBoard", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@ToString.Exclude
private final Set<ImageData> imageDataSet = new HashSet<>();
//코드 추가
public void addImageData(ImageData imageData) {
//imageDataSet에 객체 추가
imageDataSet.add(imageData);
//imageData에도 imageBoard 객체를 추가
imageData.setImageBoard(this);
}
}
// 처리 코드
void imageInsertProc(.......){
....
ImageBoard imageBoard = ImageBoard.builder()
.member(principalService.checkPrincipal(principal))
.imageTitle(request.getParameter("imageTitle"))
.imageContent(request.getParameter("imageContent"))
.imageDate(Date.valueOf(LocalDate.now())
.build();
imageInsert(...... , imageBoard);
imageBoardRepository.save(imageBoard);
....
}
//파일 처리 메소드 호출
void imageInsert(..... , ImageBoard imageBoard) {
...
ImageData imageData = ImageData.builder()
.imageName(saveName)
.oldName(originalName)
.imageStep(step)
.build();
imageBoard.addImageData(imageData);
....
}
이렇게 처리했다.
imageBoard를 먼저 빌드한 뒤 파일 처리 메소드를 호출할 때 imageBoard를 같이 넘겨준다.
그럼 파일 처리과정에서 imageData를 빌드할때는 ImageBoard를 제외한 나머지 값들로 빌드해준다.
그리고 Imageboard 엔티티에서 만들어놓은 addImageData 메소드를 통해 두 엔티티에 객체들을 저장할 수 있도록 해준다.
그리고나서 파일처리가 끝나면 Repository를 통해 save를 해주게 되면 연관관계에 있는 두 엔티티의 데이터가 한번에 저장되게 된다.
그럼 파일 처리 도중에 ImageBoard 엔티티 데이터에 대해 굳이 신경 쓸 필요도 없고 저장도 간단하게 해줄 수 있다.
Reference
https://data-make.tistory.com/730
[JPA] 양방향 관계 Entity 저장하기
JPA 양방향 관계 Entity 저장하기 인간은 습관의 동물이다. 습관에는 대부분 좋은 습관이 많지만 그중에 나쁜 습관도 있다. 그것은 바로.. 원리를 모르고 개발하는 습관이다. 😯 . '요로케할 때 이
data-make.tistory.com
'Spring' 카테고리의 다른 글
프로젝트에 WebClient 사용해보기 (0) | 2023.06.08 |
---|---|
JPA 사용중에 저장된 Entity의 ID값 알아내기 (0) | 2022.12.20 |
WebSecurityConfigurerAdapter Deprecated 해결 (0) | 2022.12.06 |
IoC와 DI(7. Bean 설정 분할과 profile별 설정) (0) | 2022.08.31 |
IoC와 DI(6. Bean Scope) (0) | 2022.08.29 |