김영한님의 JPA 강의를 듣고 정리한 내용입니다.
특정 엔티티를 영속 상태로 만들 때 연관된 엔티티도 함께 영속 상태로 만들고 싶을 때 사용한다. 하나의 부모가 자식을 관리할 때 주로 사용한다.
다음과 같은 경우에 사용한다.
1. 부모와 자식의 라이프 사이클이 거의 동일할 때
2. 단일 엔티티에 완전히 종속적일 때
연관관계 매핑 속성으로 cascade를 추가해서 설정할 수 있다.
OneToMany(mappedBy = "...", cascade = CascadeType.ALL)CASCADE는 다음과 같은 속성이 있다.
영속성 전이는 연관관계를 매핑하는 것과 아무 관련이 없다. 엔티티를 영속화할 때 연관된 엔티티도 함께 영속화하는 편리함을 제공할 뿐이다.
위에 설명한 것과 같이 소유자가 하나일 때만 사용해야 한다. 소유자가 둘 이상일 때 사용하면 의도하지 않은 방향으로 전이될 수 있음.
A-C, B-C로 CASCADE 되어 있을 때 A 삭제 시 C까지 삭제되어 의도치 않게 B에 연결되어있는 C 값이 null로 바뀌게 되는 참사 발생부모 엔티티와 연관관계가 끊어진 자식 엔티티를 자동으로 삭제하는 기능이다.
orphanRemoval 속성으로 자동 삭제 여부를 결정할 수 있다.
@Entity
class Parent {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(..., orphanRemoval = true)
@JoinColumn(name = "parent")
private List<Child> children = new ArrayList<>();
...
}
orphanRemoval 속성이 켜져있을 경우 List에서 값이 사라지면 해당 자식 엔티티도 삭제된다.
Child child1 = new Child();
child1.setName("child1");
Child child2 = new Child();
child2.setName("child2");
Parent parent = new Parent();
parent.setName("parent1");
parent.addChild(child1);
parent.addChild(child2);
em.persist(parent);
em.flush();
em.clear();
List<Child> children1 = parent.getChildren();
for (Child child : children1) {
System.out.println("child = " + child.getName()); // 1
}
Parent findParent = em.find(Parent.class, parent.getId());
findParent.getChildren().remove(0);
List<Child> children2 = findParent.getChildren();
for (Child child : children2) {
System.out.println("child = " + child.getName()); // 2
}
이 경우 1번에선 2개의 항목이 나오지만 2번에선 index = 0에 해당하는 객체가 삭제돼서 1개의 항목만 나온다.
참조가 제거된 엔티티는 다른 곳에서 참조하지 않는 고아 객체로 보고 삭제하는 기능이기 때문에 참조하는 곳이 하나일 때 사용하거나 특정 엔티티가 개인 소유할 때 사용한다.
@OneToMany 또는 @OneToOne만 사용 가능하다.
개념적으로 부모를 제거하면 자식은 고아가 된다. 따라서 고아 객체 제거 기능을 활성화 하면, 부모를 제거할 때 자식도 함께 제거된다. 이것은 CascadeType.REMOVE처럼 동작한다.
영속성 전이와 고아 객체를 더하는 것은 cascade = CascadeType.ALL + orphanRemoval = true의 의미이다.
위의 둘을 전부 켜게 되면 다음과 같은 의미를 지닌다.
em.persist()로 영속화, em.remove()로 제거한다.