[개념쌓기]CASCADE?OrphanRemoval?
중심을 만들어내는 것은
시선을 소유한 자가
디디고 선 자리이다
게시판을 만들다보니 댓글도 만들게 되었다.
삭제를 하려는데 게시판에 물려있는 댓글 때문인지 삭제를 누르면 기능이 동작하지 않았다.
구글링을 통해 이것이 CASCADE옵션의 부재임을 알게되어 한번더 정리하게 되었다
그래서뭐냐고? => 영속성에서 참조된 객체를 지워주지 않았기 때문
그리고 궁금하게 되었던 고아 객체 처리 orphanRemoval에 대해서도 알아보자
CASCADE?
- 부모 엔티티에서 자식 엔티티로 상태를 전이하는 것
ex. 부모 엔티티 저장할 때 자식 엔티티도 함께 저장, 부모 엔티티인 게시글 삭제시 자식 엔티티인 댓글도 같이 삭제
- Parent와 Child가 라이프사이클이 동일할 때,Child를 소유하는 Parent가 하나일 때 사용하는 것이 좋음
CascadeType?
CascadeType.ALL - 엔티티의 모든 상태 전이
CascadeType.PERSIST - 엔티티의 Persist(영속성)전이시에 필드에 보유된 엔티티도 유지한다.EntityManager가 flush 중에 새로운 엔티티를 참조하는 필드를 찾고 이 필드가 CascadeType.PERSIST를 사용하지 않으면 오류이므로 이 Cascade규칙의 자유로운 적용을 제안
CascadeType.REMOVE - 엔티티 삭제시, 이 필드에 보유된 엔티티도 삭제
CascadeType.Remove는 부모 엔티티가 삭제되면 자식 엔티티도 삭제된다.즉, 부모가 자식의 삭제 생명 주기를 관리하는데 만약 CascadeType.PERSIST도 함께 사용시,부모가 자식의 전체 생명 주기를 관리하게 된다.
부모 엔티티가 자식 엔티티와의 관계를 제거하면 자식 엔티티는 삭제되지 않고 그대로 남아있는다.
CascadeType.MERGE - 병합 전이시에, 필드에 보유된 엔티티도 병합
CascadeType.DETACH - 부모 엔티티가 detach()를 수행하게 되면,연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않는다
CascadeType.REFRESH - 엔티티를 새로 고칠 때,이 필드에 보유된 엔티티도 새로 고친다
문제가 발생했던 부분으로 cascade=CascadeType.ALL을 통해 게시물 삭제시 해당 게시물의 댓글이 삭제되도록 하였다.
고아객체
OrphanRemoval(고아없애기)
- 부모 엔티티와 연관관계가 끊어진 자식 엔티티 자동으로 삭제=> orphanRemoval=true
- 부모 엔티티에서 자식엔티티 list에서 remove를 한 경우
ex. phones.remove(phone);
=> 특정 엔티티가 개인 소유할때만 (즉,Child를 소유하는 Parent가 하나일 때)
orphanRemoval=true 로 쓰자
이제 다 아는 것 같다 생각해도 아직 다 아는게 아니야
형은 다 알 수가 있어
OrphanRemoval와 CascadeType.ALL의 차이가 무엇일까
CascadeType.Remove 와 orPhanRemoval = true 의 차이점은 관계가 끊어졌을 때 데이터에 대한 동작의 차이이다.
orPhanRemoval 는 부모 객체 (Member)와 자식 객체 (MemberFollow) 의 관계가 끊어졌을 때,
자식 객체의 데이터까지 삭제해주는 역할을 하고, CascadeType.Remove 는 참조를 변경시켜 무결성 오류를 안나게 할 뿐, 그 데이터는 남겨두게 된다.
따라서 두 엔티티의 관계를 끊을 때, MemberFollow 테이블의 데이터가 계속 남아있기를 바란다면,
CascadeType.Remove 만 쓰는 것이고,
MemberFollow 테이블의 해당 데이터까지 삭제를 바란다면 orPhanRemoval = true 를 사용하는 것이다.
결론적으로 다 쓰까서 쓸 때 어떻게 될까?
# cascade = CascadeType.ALL + orpahnRemoval = true
- 두 옵션을 모두 활성화하면 부모 엔티티를 통해서 자식 엔티티의 생명주기 관리 가능
- 도메인 주도 설계(DDD)의 Aggregate Root 개념을 구현할 때 유용
- 부모 엔티티 삭제 시 자식 엔티티들도 삭제됨
# cascade = CascadeType.ALL, cascade = CascadeType.REMOVE
- 부모 엔티티 삭제 시 자식 엔티티들도 삭제됨
- orpahnRemoval=true 없어도 연관관계 상태(삭제)까지 전파됨
- orpahnRemoval=true 없으므로 부모 엔티티에서 가져온 자식 엔티티 리스트에서 remove할 경우 자식 엔티티가 삭제되는건 아님!
# cascade = CascadeType.PERSIST
- 부모 엔티티 삭제 시 부모 엔티티만 삭제
- 부모 자식을 바라보는 자식 엔티티가 있을 경우 FK 제약이 때문에 에러 발생
ERROR: Referential integrity constraint violation: "FKLH67J1N7X7GT59U0PBKWQH6O6: PUBLIC.CHILD FOREIGN KEY(PARENT_ID) REFERENCES PUBLIC.PARENT(ID) (CAST(1 AS BIGINT))"; SQL statement:
# cascade = CascadeType.PERSIST + orpahnRemoval = true
- 부모 엔티티 삭제 시 자식 엔티티들도 삭제됨
- orpahnRemoval=true 있어야 자식 삭제됨