인프런 커뮤니티 질문&답변
@OneToMany , @ManyToOne 질문 있습니다.
작성
·
248
0
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.
1. 강의 내용과 관련된 질문을 남겨주세요.
2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.
(자주 하는 질문 링크: https://bit.ly/3fX6ygx)
3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.
(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)
질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)
[질문 내용]
안녕하세요 JPA 강의를 수강 후 게시판에 이미지 첨부를 구현하기 위해 공부하고 있습니다.
1.Board와 Image는 1:N 관계
2.연관관계 주인은 Board
3.cascade = CascadeType.ALL로 옵션을 주어
부모 엔티티(board)가 영속화될 때, 자식 엔티티(Image)도 함께 영속화되도록 했습니다.
위와 같이 설계를 한뒤 코드를 작성했습니다.
근데, Image와 Board 테이블에 모든 데이터가 다 들어가는데
Image 테이블의 board_id가 계속 null값이 들어갑니다.
이 부분이 잘 이해가 안되는데 원인이 무엇일까요?
코드는 아래와 같습니다 !
@Entity
@Getter @Setter
@NoArgsConstructor
public class Board {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "board_id")
private Long id;
@Column(name="title")
private String title;
@Column(name="content")
private String content;
@Column(name="writer")
private String writer;
@Column(name="date")
private String date;
/* @OneToMany(mappedBy = "board")
@Nullable
private List<Image> images = new ArrayList<>();
*/
@OneToMany(mappedBy = "board",cascade = CascadeType.ALL)
private List<Image> images = new ArrayList<>();
@Builder
public Board(String writer,String title,String content,String date,List<Image> images){
this.writer=writer;
this.title=title;
this.content=content;
this.date=date;
this.images=images;
}@Entity
@Getter
@Setter
@NoArgsConstructor
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fileName;
@ManyToOne
@JoinColumn(name = "board_id")
private Board board;
private String url;
@Builder
public Image(String fileName,String url){
this.fileName=fileName;
this.url =url;
}
}@Service
@Transactional
@RequiredArgsConstructor
public class BoardService {
private final BoardRepository boardRepository;
LocalDateTime currentTime = LocalDateTime.now(); // 현재 시간을 가져옴
/**
* Create
*/
@Transactional
public Long
saveBoard(BoardSaveRequest request,List<Image> images){
Board board= Board.builder()
.writer(request.writer())
.content(request.content())
.title(request.title())
.date(String.valueOf(currentTime))
.images(images)
.build();
board.setImages(images);
//cascade = CascadeType.PERSIST : 보드 생성 -> image add
boardRepository.save(board);
return board.getId();
}
@RestController
@RequestMapping("/board")
@RequiredArgsConstructor
@Slf4j
public class BoardController {
private final BoardService boardService;
private final ImageService imageService;
/**
* 게시글 생성
* @param writer
* @param title
* @param content
* @param images
* @return 생성된 게시글 id
*/
@PostMapping()
public ResponseEntity<ApiUtil.ApiSuccessResult<Long>> createBoard(
@RequestPart(value="writer") String writer,
@RequestPart(value="title") String title,
@RequestPart(value="content") String content,
@RequestPart(value = "images", required = false) List<MultipartFile> images) throws IOException {
BoardSaveRequest boardSaveRequest= BoardSaveRequest.builder()
.writer(writer)
.content(content)
.title(title).build();
List<Image> listImage = imageService.saveImage(images);
Long saveId = boardService.saveBoard(boardSaveRequest,listImage);
return ResponseEntity.ok().body(ApiUtil.success(HttpStatus.CREATED,saveId));
}
@Service
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
public class ImageService {
public List<Image> saveImage(List<MultipartFile> multipartFiles) throws IOException {
List<Image> images = new ArrayList<>();
for(MultipartFile m : multipartFiles){
m.transferTo(new File("/Users/parkjihyeon/Desktop/imageFolder/"+m.getOriginalFilename()));
Image image= Image.builder()
.fileName(m.getOriginalFilename())
.url("/Users/parkjihyeon/Desktop/imageFolder/"+m.getOriginalFilename())
.build();
images.add(image);
}
return images;
}
}답변 2
0
안녕하세요, 인프런 AI 인턴입니다.
파이팅파이팅님의 질문을 세심하게 읽었고, JPA에서 @OneToMany와 @ManyToOne 관계에서 board_id가 null로 설정되는 문제에 대해 해결 방안을 제시하는 내용을 찾았습니다. 문제의 핵심은 Entity 간의 연관관계 설정 시, 부모 객체에 자식 객체를 추가하더라도 자식 객체에서 부모 객체를 참조하는 관계를 명확하게 설정해주지 않으면 외래 키(board_id)가 null로 설정될 수 있다는 점입니다.
아래의 정보는 연관 관계 매핑을 할 때 상대 엔티티를 제대로 참조하지 않아 발생하는 문제점과 해결 방안에 대한 설명입니다.
1. 김영한님의 답변(직접적으로 문제를 다루진 않지만 연관 관계 설정에 관한 유용한 팁 제공)
- cascade = CascadeType.ALL질문에서, 김영한님이 cascade 옵션과 연관관계 설정에 대해 상세하게 설명하고 있습니다. 이는 Entity의 상태 변화를 전파하는 방법에 대해 이해할 수 있는 기초 지식을 제공합니다.
2. 해결 방안
- 문제 해결의 핵심은
Image엔티티 객체를 생성할 때, 그Image가 속해야 할Board엔티티의 참조(board)도 함께 설정해야 한다는 것입니다. 즉,Image객체를 생성하고images.add(image)를 통해Board에 추가할 때,image.setBoard(this)같은 방식으로Image객체에도Board를 참조하도록 해야 합니다. 이미 구현하신Board클래스에서setUser메소드가 이런 역할을 수행합니다만,Image객체에 대한Board참조 설정이 누락된 것 같습니다.
public void addImage(Image image) {
images.add(image);
image.setBoard(this);
}
이와 같은 메소드를 Board 클래스에 추가하고, 이미지를 추가할 때 이 메소드를 사용하면 Image의 board 필드가 null로 남지 않고 올바르게 참조가 설정됩니다.
3. 구현 방법
BoardService의 saveBoard 메소드 내에서 Board 객체를 생성한 후 Image 객체들을 추가할 때는 단순히 board.setImages(images)를 호출하는 것이 아니라, 각 Image 객체에 대해 위에서 생성한 addImage 메소드를 호출하여 Board 객체에 추가하십시오. 이렇게 하면 각 Image 객체가 자신이 속한 Board를 제대로 참조하게 됩니다.
Board board = Board.builder()
.writer(request.writer())
.content(request.content())
.title(request.title())
.date(String.valueOf(currentTime))
.build();
for (Image image : images) {
board.addImage(image);
}
boardRepository.save(board);
이렇게 사용할 경우, Image 엔티티에 @ManyToOne으로 설정된 Board와의 관계가 올바르게 설정되어 board_id가 올바르게 저장될 것입니다.
저는 질문자님의 이해를 돕고자 지식공유자님의 기존 답변을 참고하여 유사한 답변 링크를 추천해드리고 있습니다.
현재 베타 기능으로 답변이 만족스럽지 않을 수 있는 점 양해 부탁드립니다. 🙏
추가적으로 궁금한 점이 있으시면, 이어서 질문해 주세요. 곧 지식공유자께서 답변해 주실 것입니다.





