게시글
질문&답변
2021.02.09
OrderItem을 DB에서 지우고자 할 때
알려주셔서 감사합니다. 이제부터는 정답이 없는 고민을 하게 되는군요. 설계를 생각할 때엔 단순함을 먼저 생각하는 것을 꼭 기억하겠습니다. 개발경험을 통해 알려주신 부분 덕분에 여러 가지 감을 잡을 수 있었던 것 같습니다. 많이 도와주신 덕분에 이러한 고민도 할 수 있었던 것 같습니다. 정말 감사드립니다!
- 2
- 22
- 2.9K
질문&답변
2021.02.08
OrderItem을 DB에서 지우고자 할 때
궁금하던 부분이 해소되었습니다~! @Transactional을 벗어나면서 변경감지를 통해 id가 채워져서 나가기 때문에, 객체를 return한 뒤에 id를 사용할 수 있군요. 정말 감사합니다. 아마 아래에 드리는 질문이 이 것과 관련된 마지막 질문이 될 것 같습니다.! 위 예시에서는 객체를 찾을 때 이미 객체를 알고 있어서 참조 비교로 찾을 수 있는데, 외부 URI를 통해 들어오는 정보는 id 밖에 없어서 바로 객체 참조값을 가질 수 없어 어찌됐든 id를 통해 객체를 찾아야 하더라구요. 보통은 repository를 통해 findById로 찾을텐데, cascade와 orphanremoval로 완전히 entity에게 책임을 넘긴 상황이라면, entity의 멤버함수로 id를 받아 객체를 찾는 것이 좋은 설계일까요? 다시 정리드리면, 상황: URI를 통해 들어오는 정보만으로 객체를 찾아야하므로 id값 밖에 알 수 있는 것이 없음. (실무에서 사용하는 다른 방법이 있거나, cascade와 orphanremoval을 써서 묶은 entity를 조회하는 일이 있으면 안될 경우 알려주세요.) 해결: id로 객체를 찾기 위해 entity class에 id를 받아 객체를 반환하는 멤버함수를 만들음 (cascade와 orphanremoval로 책임을 entity에게 넘겼기 때문) 위와 같은 상황이 맞는 설계인지가 궁금합니다. 오류가 난다면 "오답"이기 때문에 "정답"으로 고치면 되지만, 설계 방식에 있어서는 실무경험이 없는 제겐 맞는 설계 방식인지 아닌지 알 수 있는 방법이 없네요.. 이에 대한 조언 주시면 감사하겠습니다.
- 2
- 22
- 2.9K
질문&답변
2021.02.06
OrderItem을 DB에서 지우고자 할 때
감사합니다. 다른 부분 모두 이해했습니다. 그런데, 마지막 질문은 제가 조금 여쭤보고 싶었던 거랑 다르네요ㅠㅠ 말씀주신 내용은 알고있는 부분인데, 제가 궁금했던 부분은 외부에서 어떻게 child 객체를 찾는지가 질문이었습니다. 변경감지를 통한 insert는 해당 메서드에서 바로 id를 읽을 수 없기 때문에 (아직 메서드가 안 끝나서 commit전이므로 id==null) Service에서 child 객체를 추가하고 id를 마지막에 return할 수 없는 상황입니다. (마치 OrderService에서 order 메서드를 마치고 id를 return해주는 것과 같은 메서드를 만들 수 없는 상황) (위에서 말씀드렸듯이, child에서도 id를 받기 위해 em.persist를 호출한 것인데, persist를 사용하면 안 된다고 하면 자동으로 id도 null로 return되어서..) 아래는 전부 게시물-첨부파일 예시로 들겠습니다. 만약 OrderService처럼 child를 add후 해당 child의 id값을 return을 해주면, view에서 뿌릴 때 id를 내주어서 DELETE /posts/1/files/2 이런식으로 1번 게시물의 2번 첨부파일을 지우라는 행동이 가능한데 반해, 만약 위처럼 변경감지에 의존하면 Service에서 id값을 return해줄 수 없고, 뿌릴 때 해봤자 index로 뿌리게 되는데, 똑같이 DELETE /posts/1/files/2 를 요청하게 되면, 2번이 사라지고 3번인 요소가 2번이 되기 때문에 문제가 생길 것 같아서요. (같은 URI에 다른 behavior가 매핑되어서요) 이 부분을 실무에서는 실제로 Controller에서 어떻게 받아서 요청하는지 궁금합니다. 제가 이해한 바로는, CASCADE로 묶어서 엔티티에게 관리주체를 넘기면, 엔티티에서 관리하기 때문에 repository에서 잘 해오던 DB로부터 id 값을 받는 일이 없을 것 같아, 이럴 때에는 어떻게 해결하는지 궁금합니다. 제 질문이 잘 전달되지 않아 아쉬워서 이렇게 조금 더 구체적으로 상황을 적어봅니다. 이렇게 질문드리는 이유는 실무에선 이런 상황일 때 어떤 패턴으로 프로그래밍하는지 궁금하여 질문드립니다. 실무에서 이런 상황이 발생하지 않고 애초에 다른 방향으로 설계한다면, 그 방향을 알려주시면 감사하겠습니다. 도와주셔서 감사합니다.
- 2
- 22
- 2.9K
질문&답변
2021.02.04
OrderItem을 DB에서 지우고자 할 때
늦게 답변드려 죄송합니다. 해결 도와주셔서 정말 감사합니다. em.persist() 호출로 인해 저장과 삭제 순서가 꼬여 발생하는 것이었군요. 정말 친절한 답변 감사드립니다! 주신 코드에서 궁금한 점이 있는데, (다른 강의지만,) mappedBy로 연결된 list는 강의 때 "mappedBy 단어 그대로 mapping이 되어있을 뿐 연관관계의 주인이 아니기 때문에 이 변수를 변경하여도 DB에 반영되지 않는다."라고 말씀주셨던 것 같은데, 위 테스트코드에선 mappedBy의 변수를 변경함으로써 제거하신 것 같아서요.! 여기서는 어떻게 변경이 된 것인지, 원래 변경을 해도 되는 변수인지 궁금합니다. 그리고, Parent.childList는 지웠지만 Child.parent는 지우지 않으셨는데, 이 부분은 (DB반영 말고도 실무에서) 문제가 없을까요? 그리고 cascade를 사용하면 관리의 주체가 리포지토리가 아닌 엔티티로 해야한다고 말씀주신 부분 이해했습니다. repository에서는 완전히 신경끄고 그 부분을 엔티티에게 넘겨야하군요. 선생님 덕분에 설계에 대해 또 한 번 배웁니다. 감사합니다. 그렇다면 parent에 연결된 특정 child를 지우기 위해서는 어떻게 해야하나요? 저 위에서 제가 em.persist()를 호출했던 이유는 생성된 OrderItem의 id를 넘겨주기 위해서였는데, 만약 save없이 변경감지에 의존하여 엔티티에서 해결해야 한다면 id 부여가 되지 않을텐데, 생성했음을 알릴 때 id를 넘겨줄 수 없기도 하고 특정 OrderItem 삭제를 원할 때 어떤 OrderItem인지 어떻게 찾을 수 있나요? 위에 적어주신 게시물-첨부파일을 예시로 들면, 게시물에 첨부파일 3개를 업로드한 뒤에 2번 첨부파일을 지우기 위한 요청을 보냈다고 하면 DELETE를 id와 함께 보내주어야할 것 같아서요.! 내부 코드에서는 index로 관리할 수 있지만, 서비스에서 OrderItem 삭제를 보낼 때엔 그 pk id가 있어야한다고 생각을 했었습니다. 질문이 길어 질문 부분에 하이라이트 하였습니다. 답변 주시면 감사하겠습니다!
- 2
- 22
- 2.9K
질문&답변
2021.01.30
OrderItem을 DB에서 지우고자 할 때
아하, 코드를 확인해야 문제를 찾을 수 있군요. 다른 사람 코드 읽는게 굉장히 시간 소모적인 것을 알기에, 제가 말씀드린 상황이 담긴 함수를 강의예시 프로젝트에 얹어서 최소한의 수정으로 설명과 함께 전달드리겠습니다. 강의 예시는 갖고 계실테니 바로 합칠 수 있도록 diff 뜬 것도 따로 전달드리겠습니다. 도와주셔서 감사합니다! 주말 내로 보내드리겠습니다.
- 2
- 22
- 2.9K
질문&답변
2021.01.30
OrderItem을 DB에서 지우고자 할 때
혹시나 해서 연관관계 끊는 함수도 단위테스트 해보았는데, 정상 작동 합니다. 처음은 orphanRemoval이 안 되는 것에 대한 질문이었지만, 알아보다보니 다음 질문으로 바뀐 것 같습니다. persist 후에 연관관계 맺어 추가된 child에 대해서는 orphanRemoval이 작동하지 않는다.(Order - OrderItem 예시로 들면, 강의에서는 OrderItem을 미리 만들고 Order에 추가한 후 영속화하였지만, 영속화 후에 OrderItem을 추가할 경우 orphanRemoval이 작동하지 않습니다.) 이렇게 정리가 되네요. 위의 요약본을 더 요약한 한줄요약입니다. 왜 이런지 아직 이해를 못 한 상황입니다..
- 2
- 22
- 2.9K
질문&답변
2021.01.29
OrderItem을 DB에서 지우고자 할 때
CASCADE 관련 질문이 많았나 보군요 ㅎㅎ 그런데 위 링크는 제 질문과 많이 다른 질문 같습니다.ㅠㅠ 제 상황이 잘 전달이 되지 않는 것 같아 짧게 요약드리자면.. 제 상황은 이렇습니다. 1. CascadeType.ALL로 묶여있음. 2. orphanRemoval = true 3. child와 연관관계 매핑 후 persist를 통해 영속화한 parent의 경우, child와 연관관계를 지움으로써 delete query 정상 발생 // pseudo code persist(new Parent(child)) 4. child 없이 parent 선 persist 후에 나중에 child와 연관관계를 맺은 후 추가로 parent를 persist를 한 경우엔 (이미 managed entity), child와 연관관계를 지워도 delete query 발생하지 않음 (대신 연관관계를 지워서 fk=null로 바꾸는 update 발생) // pseudo code persist(new Parent()) persist(parent.addChild(child)) 5. 상황3, 4번에서 모두 child와의 연관관계를 지웠기 때문에 em.remove(child)으로 삭제 가능 [위 링크와 다른 점]. 하지만, orphanRemoval을 통해 지우는 것은 불가능. 6. 4번의 경우 dirty checking으로 update되는 상황이라 생각 (child는 persist하지 않았지만, 실제로 child에 parent fk 잘 받아옴.). 하지만 상황3, 4번이 각각 다른 결과를 내는 것을 보아하니 두 작업이 다른 것을 확인. 두 작업이 다른 것은 이제 구분이 되는데, 왜 다른지, 어떻게 다른지가 궁금합니다. 디테일한 상황은 바로 직전 질문을 확인해주시면 감사하겠습니다.. 모두 요약한 내용입니다.
- 2
- 22
- 2.9K
질문&답변
2021.01.29
OrderItem을 DB에서 지우고자 할 때
링크 속 질문하신 분은, CascadeType.ALL, CascadeType.PERSIST로 하면 되는데 그 밖은 안 되는 상황에서의 질문인데, 저는 상황이 달라 이미 CascadeType.ALL 옵션을 썼지만 되지 않는 상황이었습니다. 코드 흐름이 달라 보이지 않은데 전 CascadeType.ALL로 하였을 때 왜 안 될까 싶어, 코드를 계속 살펴보고 여러 가지 시도 해보면서 상황을 조금 좁혀나가 보았습니다. 결론은, 저는 parent를 영속화한 후 child를 추가하는 상황이 있었고, 그런 상황일 때에 orphanRemoval이 작동을 하지 않았습니다. 위 설명주신 게시글-첨부파일 관계가 있다고 가정을 했을 때, public class Post { // ... @OneToMany(mappedBy = "post", cascade = CascadeType.ALL, orphanRemoval = true) private List files = new ArrayList(); } public class AttachedFile { // ... @ManyToOne(fetch = FetchType.LAZY) private Post post; } Post를 file 없이 생성하고 혼자 영속화한 뒤, 나중에 file을 생성하여 Post와 연관관계를 맺어줄 때 아래와 같이 추가해줬습니다. // 이렇게 그대로 작성하진 않았지만, 이 두 개 모두 연결했다는 의미로 작성합니다.post.files.add(attachedFile);attachedFile.setPost(post); 추가한 후에는 Post쪽에서 save를 (persist를) 해줬습니다. 저는 이렇게 할 경우 CASCADE로 묶여 있어서 dirty checking이 알아서 추가해주리라 생각하며, 영속화한 후에 추가해도 다르지 않을 것이라 생각했는데 orphanRemoval이 되지 않습니다.. 이렇게 하니, (post를 처음 persist할 때 추가하지 않은) attachedFile은 fk인 board_id는 잘 받아오지만, orphanRemoval이 되지 않더라구요. 오늘 하루종일 이거만 보고있는데, 아직 구글링으로도 답을 못 구했습니다. 혹시 이유를 알 수 있을까요?
- 2
- 22
- 2.9K
질문&답변
2021.01.26
OrderItem을 DB에서 지우고자 할 때
친절히 알려주셔서 정말 감사합니다! 위 질문은 전부 이해했습니다만, 아직 제가 이해가 안된 부분이 조금 있습니다. 제일 처음에 드린 질문 상황에서 orphanRemoval = true로 하고, 연관관계를 null로 없애도 삭제가 되지 않더라구요. (첫 질문에 리스트 되어있는 4개 모두 적용한 상태입니다.) 위에서 말씀주신대로 em.remove()로 직접 삭제하면 되긴하지만, orphanRemoval을 계속 말씀주시는 것으로 보아 원래 정상적으로 연관관계를 끊으면 삭제되어야 하는 것 같아서요! OrderItem에 연결되어 있는 연관관계는 Order와 Item 뿐인 것 같은데 (orphanRemoval 옵션이 들어간 Order와의 연관관계만 끊으면 돼야 하는 것 같은데), 어떤 부분이 문제일까요?
- 2
- 22
- 2.9K
질문&답변
2021.01.25
OrderItem을 DB에서 지우고자 할 때
설계상 Repository가 필요 없을지 잘 생각해보고, 개인 소유되는 것에 한 해 정말 필요없을 때에만 CASCADE를 사용한다는 말씀이군요. 친절한 답변 정말 감사합니다! 그렇다면, 위 답변에서 게시물에 속한 첨부파일를 예시로 들 때, 첨부파일이 완전히 게시물 소유에 Repository도 필요없을 것 같아 CASCADE로 묶어버렸는데, 나중에 게시물 삭제 없이 첨부파일만 삭제하기 위해 게시물Repository 내에 em.remove(첨부파일)과 같은 행동을 하는 함수를 넣는 것은 잘못된 설계인가요? 위 설계가 잘못된 설계인지, em.remove(첨부파일)과 같이 직접 첨부파일을 건드려야 하는 일이 있다면 첨부파일Repository 로 무조건 빼내야하는지 궁금합니다.
- 2
- 22
- 2.9K