영속성 전이
란 연관관계 매핑에 추가할 수 있는 설정으로
한 엔티티가 영속될 때, 연관된 엔티티도 같이 영속될 수 있도록 해주는 설정이다.
즉, 여러 em.persist를 하나의 em.persist로 줄여주는 설정이다.
자주 쓰이는 CascadeType에는
가 있다.
Parent
1 : * Child
의 관계를 예시로 들겠다.
Parent Entity
@Entity
public class Parent {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "parent")
private List<Child> children = new ArrayList<>();
public void addChild(Child child) {
children.add(child);
child.setParent(this);
}
}
Child Entity
@Entity
public class Child {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "parent_id")
private Parent parent;
}
위 상황은 양방향 연관관계가 매핑돼있다. 이 상황에서 일반적인 영속화는
순서이다.
하지만 이렇게 연관된 엔티티들을 일일이 영속화시키는 것은 실수가 있기 마련이다. 따라서 연관관계를 매핑하는 설정에 cascade = CascadeType.xxx
를 추가해주면 영속성을 전이할 수 있게 된다.
그렇다면 CascadeType.REMOVE
는 직관적으로 한 Entity를 삭제하면, 연관된 Entity들도 삭제된다고 생각이 든다.
실제로 em.remove(parent)
를 실행해도
Hibernate:
/* delete hellojpa.domain.Child */ delete
from
Child
where
id=?
Hibernate:
/* delete hellojpa.domain.Parent */ delete
from
Parent
where
id=?
두 개의 query가 내보내지고 있는 것을 확인할 수 있다.
Parent와 Child는 양방향 연관관계 매핑이 되어있다.
따라서
parent.getChildrent().remove(0)
을 통해 연관관계를 끊을 수 있다. 그렇다면 이는 실제로 연관된 Child Entity가 삭제되는 것일까??
정답은 아니다. 단순히 두 엔티티 사이에 연관관계만 끊어질 뿐, Child 엔티티는 삭제되지 않는다. 어쩌면 영속성 전이에 대한 개념을 확실히 하지 않았기에 이 질문에 헷갈렸을 것이다.
영속성 전이는, 한 엔티티가 영속화
/ 삭제
등의 행위가 이루어질 때 연관된 엔티티에도 같은 행위가 전이되는 것이기 때문에 당연히 연관관계를 끊는다고 해서 엔티티가 삭제되지 않는다.
우리는 연관관계를 끊는 순간 관계가 끊어지게 된 엔티티를 삭제하고 싶다.
Parent 엔티티에서 연관관계를 끊게 되면, 연관관계를 잃게된 Child 엔티티를 삭제하려면, Parent 엔티티의 연관관계 설정에 orphanRemoval = true
를 추가하면 된다. 말 그대로 고아를 삭제하는 것
이다.
상황에 따라 다르다고 생각한다.
굳이 Cascade를 사용하지 않더라도 개발하는 방식에 따라 문제없이 연관관계를 설정할 수 있다.
Parent parent = new Parent();
Child child = new Child();
parent쪽에서 연관관계를 끊는 것이 아니라 child쪽에서 연관관계를 끊게 된다면 이 설정은 필요가 없다.
// need orphanRemoval
parent.removeChild(child);
******************************
// Parent Entity의 Method
public void removeChild(Child child) {
this.children.remove(child);
}
// don't need orphanRemoval
child.removeAssociations();
em.remove(child);
******************************
// Child Entity의 Method
public void removeAssociations() {
this.parent.removeChild(this);
}
위의 두 가지 방법 중 무엇이 더 좋은 지는 개발자의 상황에 따라 다를 것이다. 이처럼 각자 개발하고자 하는 규칙을 세우고, 이에 맞는 설정을 통해 더욱 효율적인 개발을 진행하면 될 것 같다.
영속
/ 삭제
함으로써 연관된 Entity에도 똑같이 하게 해준다.