cascade의 삭제에 대해서 알아본다. 이전에 book 클래스는 PERSIST와 MERGE만 적용하고 있었다.
public class Book {
...
@ManyToOne(cascade = {cascade = CascadeType.PERSIST, cascade = CascadeType.MERGE})
@ToString.Exclude
private Publisher publisher;
...
}
* cascade 제거 확인하기 ( Book N : 1 Publisher )
@Test
void bookCascadeTest() {
Book book = new Book();
book.setName("JPA 초격자 패키지");
Publisher publisher = new Publisher();
publisher.setName("fastcampus");
book.setPublihser(publisher);
bookRepository.save(book);
Book savedBook = bookRepository.findById(1L).get();
savedBook.getPublisher().setName("슬로우캠퍼스");
bookRepository.save(savedBook);
System.out.println(publisherRepository.findAll());
Book deteledBook = bookRepository.findById(1L).get();
bookRepository.delete(deletedBook); //book만 삭제!
System.out.println(bookRepository.findAll());
System.out.println(publisherRepository.findAll()); //정상적으로 book이 삭제될까?
}
PERSIST와 MERGE만 있기 떄문에 book만 삭제한다고해도, publisher까지 삭제되지 않는다.
public class Book {
...
@ManyToOne(cascade = {cascade = CascadeType.PERSIST, cascade = CascadeType.REMOVE})
@ToString.Exclude
private Publisher publisher;
...
}
마찬가지로, cascade에 REMOVE를 추가해야 한다.
* 부모 객체를 제거하기
@Test
void bookRemoveCascadeTest() {
bookRepository.deleteById(1L);
bookRepository.findAll().forEach(book -> System.out.println(bookgetPublisher()));
//publisher도 삭제될까?
}
book 객체를 제거하면, 연관된 publisher 객체가 제거된다.
*orphanRemoval
orphanRemoval은 연관관계가 끊기는 경우 연관된 객체가 제거가 된다. 즉, 부모의 삭제여부와 상관없이 "고아"가 된다면 삭제가 된다.
@Test
void bookCascadeTest() {
Book book = new Book();
book.setName("JPA 초격자 패키지");
Publisher publisher = new Publisher();
publisher.setName("fastcampus");
book.setPublihser(publisher);
bookRepository.save(book);
Book savedBook = bookRepository.findById(1L).get();
savedBook.getPublisher().setName("슬로우캠퍼스");
bookRepository.save(savedBook);
System.out.println(publisherRepository.findAll());
Book cascadeBook = bookRepository.findById(1L).get();
cascadeBook.setPubhlisher(null); //연관관계 제거!
System.out.println(publisherRepository.findAll()); //publisher는 삭제될까?
}
REMOVE는 연관관계가 제거된다고 해도, 연관된 publisher는 삭제되지 않는다.
orphanRemoval = true를 설정하고 다시 테스트한다. 이 경우, 연관관계가 끊어지기만해도 연관된 엔티티는 삭제된다.
public class Publisher {
...
@OneToMany(orphanRemoval = true)
@JoinColumn(name = "publisher_id")
@ToString.Exclude
private List<Book> books = new ArrayList<>();
...
}
* orphanRemoval=true vs CascadeType.REMOVE
1. 부모가 삭제된다면, orphanRemoval와 REMOVE 모두 자식을 삭제한다.
2. 부모와 자식의 관계를 끊어버리면 ( ex Parent의 Child를 null로 변경)
2-1) orphanRemoval은 부모와의 관계가 끊어져 고아가 되었으므로 삭제된다.
2-2) REMOVE의 경우, 부모를 삭제한 것이 아니므로 자식을 삭제하지 않는다.
운영에서는, 보통 delete로 엔티티를 삭제하지 않는다, 대신에 private boolean deleted; 칼럼을 추가해서 삭제 여부를 변경하도록 한다. 기존 객체 이력이 남는 장점이 있다.
List<Book> findByDeletedFalse();
List<Book> findByCategoryIsNullAndDeletedFalse();
조회를 할 때 deleted 칼럼이 있다면, 꼭 DeletedFalse를 붙여서 삭제되지 않는 것들만 조회하도록 유의한다.
@Where(close = "deleted = false")
public class Book {
...
@Where를 선언하면, Book의 쿼리문을 실행할 때마다 삭제여부를 검사한다.
'학습 > DB' 카테고리의 다른 글
Native Query (0) | 2021.09.30 |
---|---|
@Transactional (0) | 2021.09.26 |
Cascade 활용하기 (0) | 2021.09.26 |
@Query 활용하기 2 (0) | 2021.09.26 |
@Query 활용하기 1 (0) | 2021.09.26 |