[JPA] 영속성 전이(CASCADE): 저장
영속성 전이를 사용하면 부모 엔티티를 저장할 때 자식 엔티티도 함께 저장할 수 있다.
영속성 전이를 사용하지 않았을때의 로직을 먼저 보자.
영속성 전이 사용
Parent
@Entity
@Getter
@Setter
public class Parent {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(mappedBy = "parent", cascade = CascadeType.PERSIST)
private List<Child> child = new ArrayList<>();
}
cascade 속성에 CascadeType.PERSIST 값을 주면 된다.
Child
@Entity
@Getter
@Setter
public class Child {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Parent parent;
}
한번 아래의 로직 수행 결과를 생각해보자.
public void logic() {
Child child1 = new Child();
Child child2 = new Child();
Parent parent = new Parent();
parent.getChild().add(child1);
parent.getChild().add(child2);
em.persist(parent);
}
부모에 자식을 추가하여 엔티티를 저장했다.
영속성 전이를 통해 부모와 자식 모두 정상적으로 저장이 될 것이다.
그런데 자식의 외래 키가 NULL이다...?
아니 선생님 외래 키 관리하는 주인을 mapped로 Child쪽에 있으니 당연히 외래 키 추가를 못하는거 아닌가요??
그래서 아래의 로직을 수행해보자.
child는 저장 조차 안된다.
child1.setParent(parent);
child2.setParent(parent);
em.persist(parent);
중요한 개념을 발견했다.
영속성 전이는 연관관계를 매핑하는 것과는 전혀 관련이 없다.
그저 연관된 엔티티를 같이 영속화해주는 편리함만 제공해줄 뿐이다.
완벽한 코드는 아래와 같다.
public void logic() {
child1.setParent(parent); // cascade는 persist만해주는거지 연관관계 매핑을 해주는게 아니다. 이거 안해주면 외래키 null이 들어감
child2.setParent(parent);
parent.getChild().add(child1);
parent.getChild().add(child2);
em.persist(parent);
}
양방향 연관관계를 추가한 다음 영속 상태로 만들자.
@JoinColumn을 적지 않아도 될까?
public class Child {
@ManyToOne
private Parent parent;
}
@JoinColumn은 외래 키 매핑시 사용한다고 배웠다.
공부하는 책에는 @JoinColumn이 생략되어있다. 어떻게 된것일까.
기본적으로 외래 키 매핑 컬럼 이름을 적어주지 않으면 대상 엔티티의 이름과 기본 키 컬럼의 이름을 조합하여 생성한다.
Child 테이블의 외래 키 컬럼인 parent_id를 p_id로 변경하면 아래의 에러가 발생한다.
org.hibernate.exception.SQLGrammarException:
could not execute statement [Unknown column 'parent_id' in 'field list'] [insert into child (parent_id) values (?)]
기본으로 생성하는 엔티티명_기본키명인 'parent_id'를 찾을 수 없다고한다.
그래서 교재의 경우 parent_id로 외래 키 이름을 일치시켜놨기에 @JoinColumn을 적어주지 않은것 같다.