반응형

cascade는 특정 Entity의 영속성 상태가 변경되었을 때 이를 연관된 Entity에도 전파시킬 지 선택하는 옵션이다.

특정 Entity에 @ElementCollecion으로 관리되던 하위 컬렉션이 @Entity로 변경되었는데 cascade 옵션이 함께 설정하지 않았다.
컬렉션은 기본적으로 부모 Entity와 한 쌍으로 움직이기 때문에 cascade 옵션이 없어도 부모 Entity와 함께 저장/삭제된다. (cascade 옵션을 ALL로 준 것 처럼 작동함)
하지만 Entity 간의 연관 관계에서는 기본적으로는 아무런 상태도 전이시키지 않기 때문에 연관을 설정할 때 cascade 옵션에 대해 고려해야한다.
@ElementCollecion으로 관리할 때에는 부모 Entity를 통해 자식 테이블에 저장이 잘 되었는데, 어느 순간부터 자식 테이블에 데이터가 쌓이지 않아서 헤매다가 영속성 전이 옵션에 대해 알게 되어서 정리한다.
영속성 전이 옵션을 통해 부모 Entity를 변경할 때 자식 Entity도 함께 변경할 수 있다.

@ElementCollection 설명

casecade 옵션

  • CascadeType.PERSIST
    • 엔티티를 영속화 할 때 연관된 엔티티도 함께 유지 (* PERSIST의 예상치 못한 동작)
    • 연관 엔티티가 DB에 이미 저장이 되어있어도 다시 persist하기 때문에 detached entity passed to persist Exception이 발생함(이경우에는 CascadeType.MERGE를 사용)
  • CascadeType.MERGE
    • 엔티티 상태를 병합 할 때, 연관된 엔티티도 함께 병합
    • 트랜잭션이 종료되고 detach 상태에서 엔티티가 merge()를 수행하게 되면 연관 엔티티의 추가 및 수정사항도 함께 적용됨
  • CascadeType.REFRESH
    • 엔티티를 새로 고칠 때, 연관된 엔티티도 새로고침
  • CascadeType.REMOVE
    • 엔티티를 삭제할 때, 연관된 엔티도 함께 삭제
  • CascadeType.DETACH
    • 부모 엔티티가 detach()를 수행하게 되면, 연관된 엔티티도 detach() 상태가 되어 변경사항이 반영되지 않음
  • CascadeType.ALL
    • 모든 Cascade 적용

예제

  • 부모(Parent) Entity
    • 하위 컬렉션과(ChildCollection)
    • 하위 Entity(ChildEntity)
@Builder
@NoArgsConstructor
@Entity
public class Parent {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ElementCollection
    @CollectionTable(name="child_collection", joinColumns = @JoinColumn(name= "parent_id", referencedColumnName = "id"))
    private Set<ChildCollection> childCollections = new HashSet<ChildCollection>();

    @OneToMany(mappedBy = "parent") //, cascade = CascadeType.ALL)
    private Set<ChildEntity> childEntities = new HashSet<ChildEntity>();
}
@Embeddable
public class ChildCollection{
    private String name;
    private String description;
}
@Builder
@Entity
public class ChildEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private Parent parent;

    private String name;

    private String description;
}


각각 컬럼에 데이터를 저장해보겠다.

...
    Set<ChildCollection> collections;
    Set<ChildEntity> entities;

    Parent parent = Parent.builder()
        .childCollections(collections)
        .childEntities(entities)
        .build();

    reposistory.save(parent);
...
  • @ElementCollection의 하위 컬렉션은 부모 Entity와 함께 저장된다.
  • @Entity 자식 엔티티는 부모 Entity와 함께 저장되지 않는다. => cascade option 설정 필요

참고링크

반응형