인프런 커뮤니티 질문&답변

스물다섯컷의흑백필름님의 프로필 이미지
스물다섯컷의흑백필름

작성한 질문수

자바 ORM 표준 JPA 프로그래밍 - 기본편

영속성 전이(CASCADE)와 고아 객체

merge과 remove, cascade에 대한 질문

작성

·

138

0

=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)

[질문 내용]
코드 먼저 보여드리겠습니다

public void execute(){
		EntityManager em = entityManagerFactory.createEntityManager();
		EntityTransaction tx = em.getTransaction();

		try {
			tx.begin();
			Writing writing = new Writing("A");
			Image image1 = new Image("order1");
			Image image2 = new Image("order2");

			image1.setWriting(writing);
			image2.setWriting(writing);
			writing.getImageList().add(image1);
			writing.getImageList().add(image2);

			em.persist(writing);
			em.flush();
			em.clear();

			Writing findWriting = em.find(Writing.class, writing.getId());
			List<Image> imageList = findWriting.getImageList();

			for (Image image : imageList) {
				em.remove(image); // 실행? 실행안됨?
			}

			System.out.println("=============persist start ==============");
			em.persist(image1);
			System.out.println("=============persist stop  ==============");

			tx.commit();
		}catch (Exception e){
			e.printStackTrace();
			tx.rollback();
		}finally {
			em.close();
		}
	}
public class Writing {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "writing_id")
    private Long id;

    @Column(name = "writing_name")
    private String name;

    @OneToMany(mappedBy = "writing", cascade = CascadeType.ALL)
    private List<Image> imageList = new ArrayList<>();
public class Image {

    @Id @GeneratedValue
    @Column(name = "order_id")
    private Long id;

    private String OrderName;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "writing_id")
    private Writing writing;

    public Image(String orderName) {
        OrderName = orderName;
    }
}

제가 여기서 궁금한건,
for (Image image : imageList) { em.remove(image); // 실행? 실행안됨? } 이 부분부터 인데,

Cascade.ALL로 설정해서, Writing과 image가 객체 관 연관관계가 설정되어 있기때문에 cascade 입장에서는 persist 하려하고, em.remove 입장에서는 삭제하려하기에 충돌이 일어나서 결국 삭제되지 않는 건 이해 했습니다.

이때 em.clear로 영속성 컨텍스트에 있는 writing와 image1, image2가 현재 detached된 상태가 맞다고라고 가정하고 제 질문은 다음과 같습니다.

1. em.remove(image) 자체의 코드가 "실행"은 되어서 detached된 image1, image2를 removed, 즉 영속성 컨텍스트에서 아에 제거 된 상태로 만든다라고 이해한게 맞는지?
2.그리고 detached된 엔티티이든, persist 되어있는 엔티티이든 둘 다 remove 하면 결과값은 "영속성 컨텍스트에서 제거"라는 것으로 똑같은지?
3. 만약 removed가 되어있다고 하면, em.persist가 다음과 같은 오류와 함께 실행 안되는 이유... 다음 에러에는 detached된 엔티티는 persist 할 수 없다는데 그렇다면 실제로 remove 된게 아닌지? 그렇다기엔 em.merge(image1)를 하면 새로운 객체를 생성해서 DB 에 저장하는데 ㅠ

=============persist start ==============

jakarta.persistence.EntityExistsException: detached entity passed to persist: com.example.jpatest.entity.Image
...

답변 1

1

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 이민혁님

우선 이 케이스는 잘못된 케이스 입니다. Writing은 Image를 관리해야 하고, Image는 remove로 따로 지우고 있는 상황입니다. 지금 처럼 두 가지 방식이 충돌나는 경우 자체를 만들면 안됩니다.

이 경우 Cascade를 제거하고, Image를 따로 삭제하거나 또는 Writing에서 orpahanRemoval을 사용해서 컬렉션에서 Image를 제거하는 방식 중에 하나를 선택하셔야 합니다. 물론 Image만 별로로 불러와서 삭제하는 방법도 있습니다.

지금과 같은 경우는 이미 잘못된 상황이기 때문에, 이런 상황 이후에 하이버네이트가 어떻게 구동하는지는 저도 잘 모르겠습니다.

감사합니다.

스물다섯컷의흑백필름님의 프로필 이미지
스물다섯컷의흑백필름

작성한 질문수

질문하기