본문 바로가기
카테고리 없음

프로젝트 에러

by ernest45 2023. 8. 21.

@Test
@DisplayName("이미 추천을 한 상태에서 비추천을 할 경우 추천을 취소하고 총 추천에 관한 수가 1에서 -1로 변경된다.")
void recommendAnswerWithExistingUpvoteAndChangeToDownvote() {

// Given
Member member = createMember();
memberRepository.save(member);

setDefaultAuthentication(member.getMemberId());

Question question = createquestion(member);
questionRepository.save(question);

Answer answer = createAnswerforRecommend(member, question);
answerRepository.save(answer);

// 이미 추천
answerRecommendService.recommendAnswer(answer.getAnswerId(), TypeEnum.UPVOTE);

// When
answerRecommendService.recommendAnswer(answer.getAnswerId(), TypeEnum.DOWNVOTE);

// Then
Answer updatedAnswer = answerRepository.findById(answer.getAnswerId()).orElse(null);
assertThat(updatedAnswer.getRecommend()).isEqualTo(-1);
}

이런 로직

 

 

 

 

 

 

 

 

 

 

public void recommendAnswer(Long answerId, TypeEnum recommendationType) {
        Long memberId = SecurityUtil.getCurrentId();

        Optional<Member> memberOptional = memberRepository.findById(memberId);
        Member member = memberOptional.orElseThrow(MemberNotFoundException::new);

        Optional<Answer> answerOptional = answerRepository.findById(answerId);
        Answer answer = answerOptional.orElseThrow(AnswerNotFoundException::new);

        AnswerRecommend existingRecommendation = answerRecommendRepository.findByAnswerAndMember(answer, member);

        Integer currentRecommendCount = answer.getRecommend();

        if (currentRecommendCount == null) {
            currentRecommendCount = 0; // 0으로 초기화 안해줘서 그런 듯
        }

        if (existingRecommendation != null) {
            if (existingRecommendation.getType() == recommendationType) {
                currentRecommendCount -= (recommendationType == TypeEnum.UPVOTE) ? 1 : -1;
                answerRecommendRepository.delete(existingRecommendation);

            } else {
                if (recommendationType == TypeEnum.DOWNVOTE) {
                    // 이미 추천한 상태에서 비추천을 요청할 경우 추천을 취소하고 비추천 증가
                    currentRecommendCount -= 1;
                    answerRecommendRepository.delete(existingRecommendation);
                    existingRecommendation.setType(recommendationType);
                    answerRecommendRepository.save(existingRecommendation);
                } else if (recommendationType == TypeEnum.UPVOTE) {
                    // 이미 비추천한 상태에서 추천을 요청할 경우 비추천을 취소하고 추천 증가
                    currentRecommendCount += 1;
                    answerRecommendRepository.delete(existingRecommendation);
                    existingRecommendation.setType(recommendationType);
                    answerRecommendRepository.save(existingRecommendation);
//                    추천 및 비추천 상태 변경 시에도 삭제된 엔티티를 다시 사용하지 않으려고
                }
            }
        } else {
            currentRecommendCount += (recommendationType == TypeEnum.UPVOTE) ? 1 : -1;
            AnswerRecommend answerRecommend = AnswerRecommend.builder()
                    .type(recommendationType)
                    .member(member)
                    .answer(answer)
                    .build();

            answerRecommendRepository.save(answerRecommend);
        }

        answer.setRecommend(currentRecommendCount);
        answerRepository.save(answer);
    }
}

 

 

 

여기서 

} else {
                if (recommendationType == TypeEnum.DOWNVOTE) {
                    // 이미 추천한 상태에서 비추천을 요청할 경우 추천을 취소하고 비추천 증가
                    currentRecommendCount -= 1;
                    answerRecommendRepository.delete(existingRecommendation);
                    existingRecommendation.setType(recommendationType);
                    answerRecommendRepository.save(existingRecommendation);
                } else if (recommendationType == TypeEnum.UPVOTE) {
                    // 이미 비추천한 상태에서 추천을 요청할 경우 비추천을 취소하고 추천 증가
                    currentRecommendCount += 1;
                    answerRecommendRepository.delete(existingRecommendation);
                    existingRecommendation.setType(recommendationType);
                    answerRecommendRepository.save(existingRecommendation);
//                    추천 및 비추천 상태 변경 시에도 삭제된 엔티티를 다시 사용하지 않으려고
                }

이 부분에서

삭제 후 저장에서 에러가 났다 

  existingRecommendation.setType(recommendationType);
                    answerRecommendRepository.save(existingRecommendation); 

찾아보니 삭제된 엔티티를 다시 사용하는 문제인데 없어도 코드가 잘 돌아갈까 의문이다;

 

찾아보니

 

answerRecommendRepository.delete(existingRecommendation);
existingRecommendation.setType(recommendationType);
answerRecommendRepository.save(existingRecommendation);

여기서 삭제하고 변경을 했던 것이다.

 

https://if1live.github.io/posts/typeorm-entity-proxy-for-save/

 

 

 

해결법업데이트 하기 (커스텀

https://brunch.co.kr/@anonymdevoo/37

 

Save는 Insert와 Update를 어떻게 구분할까

코드로 보는 spring-data-jpa (1) | Prerequisite: Spring Data JPA 기본 구조와 동작원리 아래 코드는 spring-data-jpa의 2.6.x 버전입니다. spring-data-jpa를 사용할 때 interface type으로 Repository를 정의해서 사용한다. pub

brunch.co.kr

 

 

업데이트가 원랜 없다 ?

JPA update가 헷갈리는 이유: JPA에는 수정 메서드가 없다.!

JPA의 Dirty Check

 

 

그렇다면 맨 처음 보여드린 코드에서 save메소드를 아예 사용하지 않았는데 JPA가 어떻게 엔티티의 변경을 감지하고, DB에 update 쿼리를 실행할까요??

JPA에서는 Dirty Checking을 통해 처리합니다.

Dirty Checking이란?
엔티티 매니저가 변경이 발생한 엔티티를 자동 감지하여 데이터베이스에 반영하는 것을 말합니다.

👉 Dirty Checking은 이미 영속화된 엔티티들을 대상으로만 작동합니다. 따라서, 준영속상태이거나 비영속상태인 엔티티들은 JPA에서 Dirty Checking을 진행하지 않습니다.

 

트랜잭션 에너테이션붙은 애들은 자동으로

(최초 조회 상태의 스냅샷을 찍어놓고 그거와 비교 후)

 

https://study-easy-coding.tistory.com/143

 

[JPA] JPA에서 update하는 방법, 더티체킹과 벌크연산

토이 프로젝트 게시판을 구현하면서 CRUD의 Update를 구현할 일이 있었다. update를 구현하면서 내가 원하는 동작은 테이블에서 하나의 컬럼만(이름) 수정하는 것이었지만, update query가 나갈 경우 이

study-easy-coding.tistory.com

 

 

 

 

 

 

https://hello-backend.tistory.com/159

 

Spring Data JPA를 통한 CRUD방법에 관하여..(feat 변경감지)

Spring Data JPA를 통한 CRUD방법에 관하여..(feat 변경감지) Spring Data JPA를 사용한 CRUD방법을 구현하면 어떻게 하나? 조회(Read) find나 get을 사용한다. 이 둘의 차이는 여기서 알아보자 저장(Create) save를

hello-backend.tistory.com

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

https://dev-emmababy.tistory.com/55

 

isEqualTo vs isSameTo 비교(깨알 instanceof연산자내용 포함)

Java JUnit 테스트에서 assertThat구문은 어떤조건이 참인지 확인하는 구문이다 [사용예시] assertThat구문에서 많이 사용하는 메서드인 isEqualTo 와 isSameTo를 비교해보겠다. [isSameTo] 일반 Primitive type의 변

dev-emmababy.tistory.com

isEqualTo vs isSameTo 비교(깨알 instanceof연산자내용 포함)

 

 

 

https://hwanchang.tistory.com/7

 

Spring Data JPA 사용 시 deleteById 와 delete 의 차이

Spring Data 란? Spring Data’s mission is to provide a familiar and consistent, Spring-based programming model for data access while still retaining the special traits of the underlying data store. It makes it easy to use data access technologies, relati

hwanchang.tistory.com

 

deleteById와 delete의 차이