작성
·
5.2K
3
안녕하세요
게시판에서 게시글과 업로드의 관계에서 제 생각하고 다르게 잘 안먹혀서 질문드리겠습니다.
Posts.java
@OneToMany(mappedBy = "posts" , cascade = CascadeType.ALL)
private List<Upload> uploadList = new ArrayList<Upload>();
Upload.java
@ManyToOne
@JoinColumn(name = "POSTS_ID")
private Posts posts;
게시글하고 업로드의 관계는 업로드가 완전히 게시글에 종속되어서
게시글 올릴때 업로드도 다같이 되고 게시글 지우면 fk게시글no에 맞춰 업로드도 다 지우게 해서 잘되는데
문제는 수정할때 업로드를 따른거하다가 취소하면 기존꺼를 남겨야하니까
저는 지금 화면에서 업로드한거 삭제하면 화면에서만 안보이게 하고 수정하기 버튼을 누르면 기존꺼 업로드는 다 삭제하고 업로드를 다시하는식으로 하는데 문제는 서비스단에서
@Transactional
public Long update(Long id, PostsUpdateRequestDto requestDto) {
Posts posts = postsRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다.id=" + id));
if(posts.getUploadList().size() > 0) {
List<Upload> uploadList = posts.getUploadList();
for (Upload upload : uploadList) {
Upload entity = uploadRepository.findById(upload.getId()).orElseThrow(()-> new IllegalArgumentException("해당 파일은 업습니다. id="+id));
uploadRepository.delete(entity);
}
}
Posts entity = requestDto.toEntity();
posts.update(requestDto.getTitle(), requestDto.getContent(), entity.getUploadList());
return id;
}
uploadRepository.delete(entity); 삭제를해도 안먹히더라고요 CascadeType.ALL는 무조건 post가 지워질때만 upload도 지워지나요?
답변 6
6
안녕하세요. 이순곤님^^
다들 한번쯤 경험하는 문제입니다. ㅎㅎ
결론부터 말씀드리면 upload를 삭제해도, post->upload 연관관계가 cascade로 남아있기 때문에 삭제가 안됩니다.
em.remove()와 post->upload의 cascade 연관관계가 서로 충돌하는 것이지요. 하나는 지우려 하고, 하나는 cascade 관계인데 연관관계에 객체가 남아있으니 저장하려고 하고... 그래서 삭제되지 않고, 남아있습니다.
해결방법은 post->upload의 연관관계를 다음처럼 끊어주면 됩니다.
post.getUploadList().remove(findUpload);
그려면 연관관계가 없으니 cascade의 효과가 사라지겠지요^^
추가로 다음 글도 읽어보시면 도움이 되실꺼에요: https://www.inflearn.com/questions/31969
전체 테스트 코드도 남겨드립니다.
package com.example.cascadetest;
import com.example.cascadetest.entity.Post;
import com.example.cascadetest.entity.Upload;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import javax.persistence.EntityManager;
@DataJpaTest
class CascadeTestApplicationTests {
@Autowired
EntityManager em;
@Test
void cascade() {
//given
Post post = new Post();
Upload upload = new Upload();
post.addUpload(upload);
em.persist(post);
em.flush();
em.clear();
//when
Post findPost = em.find(Post.class, post.getId());
Upload findUpload = findPost.getUploadList().get(0);
//cascade 때문에 객체 연관관계 남아있으면 삭제 안됨,
//객체 연관관계가 남아있으면, cascade 때문에 post -> upload 관계가 남아있다고 생각해서 삭제가 안됨
findPost.getUploadList().remove(findUpload);
//em.remove을 생략하려면 post -> upload 관계에 orphanRemoval=true 추가 필요
em.remove(findUpload);
em.flush();
em.clear();
//then: upload는 제거되어야 한다.
Upload removedUpload = em.find(Upload.class, upload.getId());
Assertions.assertThat(removedUpload).isNull();
}
}
도움이 되셨길 바래요^^
1
1
안녕하세요
아닙니다 ㅋㅋ 해결했습니다 덕분에 마이바티스 쓰던 개인 포폴 jpa로 전환하면서 이직 성공해서
지금은 자바스크립트 파이썬 갈아타서 노드js 리덕스 쓰고 있네요 ㅋㅋ
항상 좋은 강의 감사했습니다
1
안녕하세요. 순곤님
답글이 오래되면 메일로 안와서 확인이 많이 늦었습니다.
해당 오류는 다른 문제인 듯 합니다. 혹시 아직까지 해결이 안되고 고민이 남아있으시면 새로 질문글 올려주시면 도움을 드릴게요.
감사합니다.
1
0
TT 다시 한번 여쭤봐서 죄송합니다만
삭제는 잘되는데 왜 업데이트가 안되는지 이해가 안되네여
@Transactional
public Long update(Long id, PostsUpdateRequestDto requestDto) {
Posts posts = postsRepository.findById(id).orElseThrow(() -> new IllegalArgumentException("해당 게시글이 없습니다.id=" + id));
if(posts.getUploadList().size() > 0) {
List<Upload> uploadList = posts.getUploadList();
uploadList.clear();
}
Posts entity = requestDto.toEntity();
posts.update(requestDto.getTitle(), requestDto.getContent(), entity.getUploadList());
return id;
@Getter
@NoArgsConstructor
@Entity
@Table(name = "POSTS")
public class Posts extends BaseTimeEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(length = 500, nullable = false)
private String title;
@Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
@OneToMany(mappedBy = "posts" , cascade = CascadeType.ALL , orphanRemoval = true)
private List<Upload> uploadList = new ArrayList<Upload>();
@OneToMany(mappedBy = "posts" , cascade = CascadeType.ALL)
private List<Like> likeList = new ArrayList<Like>();
public void addUpload(Upload upload) {
uploadList.add(upload);
upload.setPosts(this);
}
public void addlike(Like like) {
likeList.add(like);
like.setPosts(this);
}
@Builder()
public Posts(String title, String content, String author,List<PostsUploadRequestDto> postsUploadRequestDto){
this.title = title;
this.content = content;
this.author = author;
if(postsUploadRequestDto.size() > 0 ){
for(PostsUploadRequestDto attachedFile : postsUploadRequestDto){
System.out.println("line 59 : " + attachedFile.getFileName());
Upload upload = attachedFile.toEntity();
addUpload(upload);
}
}
}
public void update(String title, String content){
this.title = title;
this.content = content;
}
public void update(String title, String content, List<Upload> uploadList){
this.title = title;
this.content = content;
this.uploadList = uploadList;
}
}
Post와 Upload 관계에서 @OneToMany(mappedBy = "posts" , cascade = CascadeType.ALL , orphanRemoval = true)추가해서
기존 post.no에 해당하는 upload uploadList.clear();를 통해 다 지우고 업데이트를 통해 들어온 새로운 upload를 영속성컨텍스트에 아직 엔티티가 포함되어있어서 entity 객체 값만 바꾸면 트랙잭션 끝나는 시점에 해당 테이블 변경분 반영하는데 더티체킹통해서 근데
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.leesungon.book.springboot.domain.posts.upload.Upload.posts -> com.leesungon.book.springboot.domain.posts.Posts
이런 에러가 뜨는데 왜 그럴까요TT