Error

org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance

2023. 5. 1. 13:03
@Data
@NoArgsConstructor
@Entity
public class Post extends BaseTimeEntity {

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

    @Column
    private String title;

    @Column
    private String summary;

    @Column
    private String broadcastId;

    @Column(columnDefinition = "TEXT")
    private String content;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "MEMBER_ID")
    private Member member;

    @OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE, orphanRemoval = true)   //Post에서만 youtube 참조
    private List<Youtube> youtubes = new ArrayList<>();

    @OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE) //Member에서도 참조
    private List<Good> goods = new ArrayList<>();

    @OneToMany(mappedBy = "post", cascade = CascadeType.REMOVE, orphanRemoval = true)   //Post에서만 Report 참조
    private List<Report> reports = new ArrayList<>();


    public Post(String title, String summary, String broadcastId, String content, Member member) {
        this.title = title;
        this.summary = summary;
        this.broadcastId = broadcastId;
        this.content = content;
        this.member = member;
    }

    @Builder
    public Post(String title, String summary, String broadcastId, String content, Member member, List<Youtube> youtubes, List<Good> goods) {
        this.title = title;
        this.summary = summary;
        this.broadcastId = broadcastId;
        this.content = content;
        this.member = member;
        this.youtubes = youtubes;
        this.goods = goods;
    }

    public void update(String title, String summary, String content, List<Youtube> youtubes) {
        this.title = title;
        this.summary = summary;
        this.content = content;
        this.youtubes = youtubes;
    }

    //연관관계 메서드
    public void addYoutube(Youtube youtube) {
        this.youtubes.add(youtube);
    }

    public void addGood(Good good) {
        this.goods.add(good);
    }

    public void addReport(Report report) {
        this.reports.add(report);
    }
}

게시글 수정 기능을 구현하던 중 에러가 발생하였다.

Hibernate에서 자식 객체를 삭제하거나 부모 객체와 연관성을 끊었지만, 변경 내용을 아직 저장하지 않은 경우 발생한다.

 

기존

/** 게시글 수정 */
    @Transactional
    public Long update(Long postId, PostUpdateRequestDto updateRequestDto) {
        Post findPost = postRepository.findById(postId).orElseThrow(() -> new IllegalArgumentException("해당 글이 없습니다. id=" + postId));
        List<Youtube> youtubes = youtubeRepository.findByPost(findPost);
        for (Youtube youtube : youtubes) {
            youtubeRepository.delete(youtube);
        }

        if (updateRequestDto.getReference().size() > 0) {
            ArrayList<String> list = updateRequestDto.getReference();
            for (int i = 0; i < list.size(); i++) {
                youtubeRepository.save(updateRequestDto.toEntity(findPost, list.get(i)));
            }
            youtubes = youtubeRepository.findByPost(findPost);
        } else {
            youtubes = null;
        }
        findPost.update(updateRequestDto.getTitle(), updateRequestDto.getSummary(), updateRequestDto.getContent(), youtubes);
        return postId;
    }

 

변경

/** 게시글 수정 */
    public Long update(Long postId, PostUpdateRequestDto updateRequestDto) {
        Post findPost = postRepository.findById(postId).orElseThrow(() -> new IllegalArgumentException("해당 글이 없습니다. id=" + postId));
        List<Youtube> youtubes = youtubeRepository.findByPost(findPost);

        findPost.getYoutubes().clear();

        List<Youtube> youtubeList = new ArrayList<>();

        if (updateRequestDto.getReference().size() > 0) {   //유튜브 링크가 있는 경우
            ArrayList<String> list = updateRequestDto.getReference();

            //Post 엔티티의 유튜브 컬렉션에 유튜브 엔티티 추가
            for (int i = 0; i < list.size(); i++) {
                Youtube saveYoutube = youtubeRepository.save(updateRequestDto.toEntity(findPost, list.get(i)));
                youtubeList.add(saveYoutube);
            }
            findPost.update(updateRequestDto.getTitle(), updateRequestDto.getSummary(), updateRequestDto.getContent(), youtubeList);
        } else {
            findPost.update(updateRequestDto.getTitle(), updateRequestDto.getSummary(), updateRequestDto.getContent());
        }

        return postId;
    }

코드를 위처럼 수정하였지만, 여전히 같은 문제가 발생했다.

 

컬렉션을 clear()로 비우면 연관관계가 끊어지고 컬렉션에 새로운 객체가 들어온 후 플러시가 되면 원래 들어있던 객체는 관계가 끊어졌기 때문에 db에서도 삭제되고 변경된 내용은 저장이 될 줄 알았다.

 

컬렉션을 비웠지만 플러시를 하지 않은 상태로 내용이 변경되었기 때문에 고아 객체 제거는 적용 되지 않는 것 같다.

 

이 경우 고아 객체 제거 기능 대신 컬렉션을 비우고 직접 db에서 delete를 해줘야 할 것 같다.

 

 

최종 변경

/** 게시글 수정 */
    public Long update(Long postId, PostUpdateRequestDto updateRequestDto) {
        Post findPost = postRepository.findById(postId).orElseThrow(() -> new IllegalArgumentException("해당 글이 없습니다. id=" + postId));
        List<Youtube> youtubes = youtubeRepository.findByPost(findPost);

        findPost.getYoutubes().clear();

        for (Youtube youtube : youtubes) {
            youtubeRepository.delete(youtube);
        }

        if (updateRequestDto.getReference().size() > 0) {
            ArrayList<String> list = updateRequestDto.getReference();

            //Post 엔티티의 유튜브 컬렉션에 유튜브 엔티티 추가
            for (int i = 0; i < list.size(); i++) {
                Youtube saveYoutube = youtubeRepository.save(updateRequestDto.toEntity(findPost, list.get(i)));
                findPost.addYoutube(saveYoutube);
            }
        }
        findPost.update(updateRequestDto.getTitle(), updateRequestDto.getSummary(), updateRequestDto.getContent());

        return postId;
    }

'Error' 카테고리의 다른 글

org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException  (0) 2023.05.01
com.fasterxml.jackson.databind.exc.InvalidDefinitionException  (0) 2023.04.01
status":415,"error":"Unsupported Media Type  (0) 2023.03.31
org.springframework.beans.factory.UnsatisfiedDependencyException  (0) 2023.03.28
[missing_user_info_uri] Missing required UserInfo Uri in UserInfoEndpoint for Client Registration  (0) 2023.03.16
'Error' 카테고리의 다른 글
  • org.springframework.context.ApplicationContextException: Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
  • com.fasterxml.jackson.databind.exc.InvalidDefinitionException
  • status":415,"error":"Unsupported Media Type
  • org.springframework.beans.factory.UnsatisfiedDependencyException
ewok
ewok
ewok
기록장
ewok
전체
오늘
어제
  • 분류 전체보기
    • 웹개발 교육
      • HTML
      • CSS
      • JavaScript
      • Database
      • Java
      • jQuery
      • Ajax
      • Bootstrap
      • jsp
      • Spring
      • MyBatis
      • 프로젝트
    • JAVA
    • SpringBoot
      • 기초
      • AWS
      • 개인프로젝트
    • Spring Security
    • JPA
    • 테스트코드
    • Error
    • CS
      • 컴퓨터 구조
      • 이산수학
    • 알고리즘
      • 정리
      • Java
    • SQL
    • 자격증
      • SQLD
      • 정보처리기사
    • Git

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • merge commit
  • 브랜치
  • sqld 합격
  • 생성자
  • GIT
  • 노랭이
  • base
  • 버전 관리
  • sqld 자격증
  • git bash
  • this
  • SQLD
  • org.hibernate.tool.schema.spi.CommandAcceptanceException
  • branch
  • org.springframework.beans.factory.UnsatisfiedDependencyException

최근 댓글

최근 글

hELLO · Designed By 정상우.
ewok
org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.