영속성 전이와 고아 객체
특정 엔티티의 영속성을 변경하는 '영속성 전이' 와 연관관계가 끊어진 '고아 객체' 에 대해 알아보겠습니다.
영속성 전이
특정 엔티티의 영속성 상태 변경 시에 연관된 엔티티의 상태가 변경되는 것을 의미한다.
[예시 : @OneToMany]
public @interface OneToMany {
Class targetEntity() default void.class;
CascadeType[] cascade() default {};
FetchType fetch() default FetchType.LAZY;
String mappedBy() default "";
boolean orphanRemoval() default false;
}
- casade() : 해당 어노테이션은 영속성 전이를 설정하는 데에 활용된다.
영속성 전이 타입의 종류
종류 | 설명 |
ALL | 모든 영속 상태 변경에 대해 영속성 전이를 적용 |
PERSIST | 엔티티가 영속화할 때 연관된 에티티도 함께 영속화 |
MERGE | 엔티티를 영속성 컨텍스트에 병합할 때 연관된 엔티티도 병합 |
REMOVE | 엔티티를 제거할 때 연관된 엔티티도 제거 |
REFRESH | 엔티티를 새로고침할 때 연관된 엔티티도 새로고침 |
DETACH | 엔티티를 영속성 컨텍스트에서 제외하면 연관된 엔티티도 제외 |
- 영속성 전이에 사용되는 타입은 엔티티 생명주기와 연관되어 있다.
- casade( ) 요소의 값으로 영속 상태의 변경이 일어나면 매핑으로 연관된 엔티티에도 동일한 동작이 일어나도록 전이하는 것이다.
- casade( ) 요소의 리턴 타입은 배열 형식이다.
영속성 전이 적용
[예시] 상품 엔티티와 공급업체 엔티티
한 가게가 새로운 공급업체와 계약하며 새로운 상품을 입고시키는 상황에 영속성 전이가 적용되는 것을 확인
공급업체 엔티티에 영속성 전이 설정
public class Provider extends BaseEntity {
//.. 중략
@OneToMany(mappedBy = "provider", cascade = CascadeType.PERSIST)
@ToString.Exclude
private List<Product> productList = new ArrayList<>();
}
영속성 전이 테스트
@Test
void cascadeTest() {
Provider provider = savedProvider("새로운 공급 업체");
Product product1 = savedProduct("펜", 1000, 100);
Product product2 = savedProduct("가방", 10000, 1000);
Product product3 = savedProduct("가위", 5000, 500);
//연관관계 설정
product1.setProvider(provider);
product2.setProvider(provider);
product3.setProvider(provider);
provider.getProductList().addAll(Lists.newArrayList(product1, product2, product3));
providerRepository.save(provider);
}
- 공급업체 1개와 상품 객체를 3개 생성한다.
- 영속성 전이 테스트를 위해 객체에는 영속화 작업을 하지 않고, 연관관계(setProvider) 만 설정한다.
- "providerRepository.save(provider)" 부분은 영속성 전이가 수행되는 부분이다.
- 영속성 전이를 사용하면 부모엔티티가 되는 Provider 엔티티만 저장하면 코드에 작성되어 있는 Cascade.PERSIST 에 맞춰서 상품 엔티티도 함께 저장이 가능하다.
고아 객체
- JPA에서 고아(orpahn)는 부모 엔티티와 연관관계가 끊어진 엔티티를 의미한다.
- JPA에는 이러한 고아 객체를 자동으로 제거하는 기능이 있다.
- 자식 엔티티가 다른 엔티티와 연관관계를 가지고 있다면 해당 기능은 사용하지 않는 것이 좋다.
공급업체 엔티티에 고아 객체 제거 기능 추가
public class Provider extends BaseEntity {
//..중략
@OneToMany(mappedBy = "provider", cascade = CascadeType.PERSIST, orphanRemoval = true)
@ToString.Exclude
private List<Product> productList = new ArrayList<>();
}
- 'orphanRemoval = true' 속성은 고아 객체를 제거하는 기능이다.
고아 객체 제거 기능 테스트
- 테스트 연관 매핑 수행 : 공급 업체 엔티티 1개, 상품 엔티티 3개
- 첫 번째 매핑 상품 엔티티 삭제 : 연관관계가 끊긴 상품의 엔티티가 제거된다.
@Test
void orphanRemovalTest() {
Provider provider = savedProvider("새로운 공급 업체");
Product product1 = savedProduct("펜", 1000, 100);
Product product2 = savedProduct("가방", 10000, 1000);
Product product3 = savedProduct("가위", 5000, 500);
product1.setProvider(provider);
product2.setProvider(provider);
product3.setProvider(provider);
provider.getProductList().addAll(Lists.newArrayList(product1, product2, product3));
providerRepository.saveAndFlush(provider);
providerRepository.findAll().forEach(System.out::println);
productRepository.findAll().forEach(System.out::println);
Provider foundProvider = providerRepository.findById(1L).get();
foundProvider.getProductList().remove(0); //첫번째 인덱스 임의 삭제
providerRepository.findAll().forEach(System.out::println);
productRepository.findAll().forEach(System.out::println);
}
반응형
'Book > 스프링부트 핵심가이드' 카테고리의 다른 글
@Validated, 커스텀 어노테이션을 이용한 유효성 검사 (0) | 2023.11.23 |
---|---|
연관관계 매핑(of. 다대다(N:N) 매핑) (1) | 2023.11.14 |
연관관계 매핑(of. 다대일(N:1), 일대다(1:N) 매핑) (0) | 2023.11.14 |
댓글