-
카테고리
-
세부 분야
백엔드
-
해결 여부
미해결
고아 객체 생성 조건
23.02.24 19:09 작성 23.02.24 19:18 수정 조회수 398
4
안녕하세요 영한님!
질문드립니다.
고아 객체는 부모 엔티티와 연관관계가 끊어진 자식 엔티티 라고 이해했습니다.
고아 객체가 생성되는 조건은
부모 엔티티 삭제
부모 엔티티가 삭제 되면 자식 엔티티를 고아객체로 판단 합니다.e.g)
em.remove(parent);
부모 엔티티에 있는 자식 엔티티 컬렉션 제거
연관관계가 끊어진 자식 객체를 고아객체로 판단 합니다.e.g)
parent.getChild().remove(0);
결과적으로 orphanRemoval = true
를 설정하면
자식 엔티티(고아 객체)는 부모 엔티티와 함께 삭제 되거나
자식 엔티티(고아 객체)만 삭제 된다.
맞게 이해하고 있는 것 일까요?
감사합니다.^^
답변을 작성해보세요.
1
김영한
지식공유자2023.02.24
안녕하세요. 개발하는쿼카님^^
제가 직접 정답을 알려드릴 수 도 있지만, 그러면 더 많은 것을 얻어가지 못합니다.
개발자는 궁금한 부분을 직접 코드로 테스트 해볼 때 가장 많이 배울 수 있습니다.
해당 부분을 코드로 직접 테스트해보시고, 그 결과를 공유해주세요. 그러면 함께 공부하는 분들께도 큰 도움이 될거에요.
그럼 테스트 해보시고 결과도 정리해서 공유 부탁드립니다.
감사합니다.
개발하는쿼카
질문자2023.02.25
답변 감사의 말씀 드립니다. 영한님^^!
제가 테스트 한 내용을 공유 드립니다.
테스트 결과 공유 드립니다.!
테스트 결과 고아객체 생성 조건은 다음과 같이 2가지 입니다.
부모 엔티티 삭제
부모 엔티티가 삭제 되면 자식 엔티티를 고아객체로 판단 합니다.e.g)
em.remove(parent);
부모 엔티티에 있는 자식 엔티티 컬렉션 제거
연관관계가 끊어진 자식 객체를 고아객체로 판단 합니다.e.g)
parent.getChild().remove(0);
제가 이해하고 있는 것이 맞았습니다!🤗
orphanRemoval = true를 설정 🙆♂️
File
@Entity
@Getter @Setter
public class File {
@Id
@GeneratedValue
private Long id;
private String name;
private String path;
// 연관관계 주인
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "file_id")
private Post post;
}
Post
@Entity
@Getter @Setter
public class Post {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "post", orphanRemoval = true)
private List<File> files = new ArrayList<>();
public void changePost(File file) {
files.add(file);
file.setPost(this);
}
}
실험 <부모 엔티티 삭제(em.remove(parent);
)>
tx.begin();
File file1 = new File();
file1.setName("둘리");
file1.setPath("/image/둘리.png");
File file2 = new File();
file2.setName("도우너");
file2.setPath("/image/도우너.png");
Post post = new Post();
post.setName("아기공룡 둘리");
post.changePost(file1);
post.changePost(file2);
em.persist(post);
em.persist(file1);
em.persist(file2);
em.flush();
em.clear();
// 부모 엔티티 삭제
Post findPost = em.find(Post.class, post.getId());
em.remove(findPost);
tx.commit();
결과
Hibernate:
/* insert com.study.purejpa.Post
*/ insert
into
Post
(name, id)
values
(?, ?)
Hibernate:
/* insert com.study.purejpa.File
*/ insert
into
File
(name, path, file_id, id)
values
(?, ?, ?, ?)
Hibernate:
/* insert com.study.purejpa.File
*/ insert
into
File
(name, path, file_id, id)
values
(?, ?, ?, ?)
Hibernate:
select
post0_.id as id1_11_0_,
post0_.name as name2_11_0_
from
Post post0_
where
post0_.id=?
Hibernate:
select
files0_.file_id as file_id4_5_0_,
files0_.id as id1_5_0_,
files0_.id as id1_5_1_,
files0_.name as name2_5_1_,
files0_.path as path3_5_1_,
files0_.file_id as file_id4_5_1_
from
File files0_
where
files0_.file_id=?
Hibernate:
/* delete com.study.purejpa.File */ delete
from
File
where
id=?
Hibernate:
/* delete com.study.purejpa.File */ delete
from
File
where
id=?
Hibernate:
/* delete com.study.purejpa.Post */ delete
from
Post
where
id=?
부모 엔티티를 삭제하면(em.remove(findPost);
) 자식 엔티티가 먼저 삭제되고, 부모 엔티티가 삭제되는 것을 확인할 수 있습니다.
마치 CascadeType.REMOVE
처럼 동작 합니다.!!!
실험 <부모 엔티티에 있는 자식 엔티티 컬렉션 제거(parent.getChild().remove(0);
)>
tx.begin();
File file1 = new File();
file1.setName("둘리");
file1.setPath("/image/둘리.png");
File file2 = new File();
file2.setName("도우너");
file2.setPath("/image/도우너.png");
Post post = new Post();
post.setName("아기공룡 둘리");
post.changePost(file1);
post.changePost(file2);
em.persist(post);
em.persist(file1);
em.persist(file2);
em.flush();
em.clear();
Post findPost = em.find(Post.class, post.getId());
// 부모와 연관관계 끊기
// 자식 엔티티를 컬렉션에서 제거
findPost.getFiles().remove(0);
tx.commit();
결과
Hibernate:
/* insert com.study.purejpa.Post
*/ insert
into
Post
(name, id)
values
(?, ?)
Hibernate:
/* insert com.study.purejpa.File
*/ insert
into
File
(name, path, file_id, id)
values
(?, ?, ?, ?)
Hibernate:
/* insert com.study.purejpa.File
*/ insert
into
File
(name, path, file_id, id)
values
(?, ?, ?, ?)
Hibernate:
select
post0_.id as id1_11_0_,
post0_.name as name2_11_0_
from
Post post0_
where
post0_.id=?
Hibernate:
select
files0_.file_id as file_id4_5_0_,
files0_.id as id1_5_0_,
files0_.id as id1_5_1_,
files0_.name as name2_5_1_,
files0_.path as path3_5_1_,
files0_.file_id as file_id4_5_1_
from
File files0_
where
files0_.file_id=?
Hibernate:
/* delete com.study.purejpa.File */ delete
from
File
where
id=?
부모 엔티티와 자식 엔티티의 연관관계가 끊어지니 자식 엔티티에 대한 delete SQL
이 발생 했습니다.!!
이때 orphanRemoval
을 적용하기 위해서는 CascadeType.PERSIST
를 포함시켜야합니다.
https://www.inflearn.com/questions/137740/orphanremoval%EA%B3%BC-cascade%EC%9D%98-%EA%B4%80%EA%B3%84
orphanRemoval = true를 설정 🙅♂️
File
@Entity
@Getter @Setter
public class File {
@Id
@GeneratedValue
private Long id;
private String name;
private String path;
// 연관관계 주인
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "file_id")
private Post post;
}
Post
@Entity
@Getter @Setter
public class Post {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "post")
private List<File> files = new ArrayList<>();
public void changePost(File file) {
files.add(file);
file.setPost(this);
}
}
실험
tx.begin();
File file1 = new File();
file1.setName("둘리");
file1.setPath("/image/둘리.png");
File file2 = new File();
file2.setName("도우너");
file2.setPath("/image/도우너.png");
Post post = new Post();
post.setName("아기공룡 둘리");
post.changePost(file1);
post.changePost(file2);
em.persist(post);
em.persist(file1);
em.persist(file2);
em.flush();
em.clear();
Post findPost = em.find(Post.class, post.getId());
// 부모와 연관관계 끊기
findPost.getFiles().remove(0);
tx.commit();
결과
Hibernate:
/* insert com.study.purejpa.Post
*/ insert
into
Post
(name, id)
values
(?, ?)
Hibernate:
/* insert com.study.purejpa.File
*/ insert
into
File
(name, path, file_id, id)
values
(?, ?, ?, ?)
Hibernate:
/* insert com.study.purejpa.File
*/ insert
into
File
(name, path, file_id, id)
values
(?, ?, ?, ?)
Hibernate:
select
post0_.id as id1_11_0_,
post0_.name as name2_11_0_
from
Post post0_
where
post0_.id=?
Hibernate:
select
files0_.file_id as file_id4_5_0_,
files0_.id as id1_5_0_,
files0_.id as id1_5_1_,
files0_.name as name2_5_1_,
files0_.path as path3_5_1_,
files0_.file_id as file_id4_5_1_
from
File files0_
where
files0_.file_id=?
지연로딩으로 설정했기 때문에 findPost.getFiles().remove(0);
시점에서 select * from File ... SQL
이 발생합니다.
그리고 orphanRemoval
를 따로 설정하지 않아서 부모 엔티티와 자식 엔티티의 연관관계가 끊어졌음에도 delete SQL
이 발생하지 않았습니다.!
감사합니다.^^
답변 1