자바 코드의 코딩 스타일대로 하면 아래와 같이 book 엔티티와 publisher엔티티를 만들때 Save하고 연관관계를 설정한 뒤 save하는 등 save 메서드들을 불필요하게 반복해서 사용하지 않고 연관관계까지 모든 설정을 마치고 한번에 Save를 하며 DB에 올릴 것이다.
하지만 그렇게 하면 연관관계를 설정하는 코드에서 DB에 해당 entity들이 들어있지 않아 오류가 발생하게된다. 그래서 relation annotation의 cacade속성을 사용하여 설정해야한다.
void BookCascadeTest() {
Book book = new Book();
book.setName("모든 순간이 너였다");
//bookRepository.save(book);
Publisher publisher = new Publisher();
publisher.setName("패스트 캠퍼스");
//publisherRepository.save(publisher);
// 연관관계 추가
book.setPublisher(publisher);
bookRepository.save(book);
// 연관관계 추가
publisher.getBook().add(book);
publisher.addBook(book);
publisherRepository.save(publisher);
System.out.println("books : "+bookRepository.findAll());
System.out.println("publisher : "+publisherRepository.findAll());
}
@Entity
@NoArgsConstructor
@Data
public class Book extends BaseEntity {
.....
@ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE})
@ToString.Exclude
private Publisher publisher;
.....
}
void BookCascadeTest() {
Book book = new Book();
book.setName("모든 순간이 너였다");
//bookRepository.save(book);
Publisher publisher = new Publisher();
publisher.setName("패스트 캠퍼스");
//publisherRepository.save(publisher);
// 연관관계 추가
book.setPublisher(publisher);
bookRepository.save(book);
// 연관관계 추가
publisher.getBook().add(book);
publisher.addBook(book);
publisherRepository.save(publisher);
System.out.println("books : "+bookRepository.findAll());
System.out.println("publisher : "+publisherRepository.findAll());
}
글의 시작에 처음 보여줬던 해당 코드의 경우는 연관관계를 mapping하는 과정에서 DB에 해당 entity들이 들어있지 않아 오류가 발생하게된다고 했었다.
이제 이러한 오류는 cascade설정을 통해 쉽게 해결 가능하다.
위의 예제의 경우는 CascadeType.PERSIST속성을 넣어주면 바로 해결할 수 있다. 해당 속성은 해당 엔티티가 persist될 때 연관관계에 있는 엔티티도 자동으로 persist시키라는 명령어로 해당 속성을 넣어주면 위의 코드로 DB에 엔티티가 들어있지 않다는 오류를 없앨 수 있을 것이다.
Book book1 = bookRepository.findById(1L).get();
book1.getPublisher().setName("성원 출판사");
bookRepository.save(book1);
System.out.println("books : "+bookRepository.findAll());
System.out.println("publisher : "+publisherRepository.findAll());
연관관계에 있는 객체의 값 업데이트를 연속적으로 하기 위해서는 reloation annotation에 CascadeType.MERGE를 추가해줘야 한다.
Book book2 = bookRepository.findById(2L).get();
bookRepository.delete(book2);
// bookRepository.deleteById(1L);
@OneToMany(orphanRemoval = true)
@JoinColumn(name = "publisher_id")
@ToString.Exclude
private List<Book> book = new ArrayList<>();
🚨 CascadeType.REMOVE VS orphanRemoval
- 부모 엔티티 삭제
둘 다 부모 엔티티를 삭제하면 자식 엔티티도 삭제한다.- 부모 엔티티에서 자식 엔티티 제거
CascadeType.REMOVE은 자식 엔티티가 그대로 존재하지만, orphanRemoval=true는 자식 엔티티를 제거한다.