Soft Delete가 안된다❓(@Where 어노테이션 주의사항)

Sol's·2023년 1월 8일
0

오류

목록 보기
9/18

좋아요 기능시 에러발생

아래 코드는 좋아요 기능이다.
좋아요 기능에 알림기능까지 넣었다.

그런데 좋아요 기능이 제대로 작동하지 않았다... soft delete처럼 삭제를 하면 deleteAt에 LocalDateTime이 찍히지만,
삭제된 좋아요를 다시 누르면 deleteAt의 LocalDateTime이 null이 되는게 아니라 새로운 Like가 생겼다...
그래서 코드를 자세히 디버깅 해보았다.

private String clickLike(Post post, User user) {
        //삭제가 되면 조회가 안되게 해놨기 때문에 중복으로 만들어진다...
        // 해결해야함...

        Optional<Like> like = likeRepository.findByPostIdAndUserId(post.getId(), user.getId());
        Optional<Alarm> targetAlarm = alarmRepository.findByTargetId(post.getId());

        if (like.isPresent()) { //좋아요가 있다는 뜻.
            Like result = like.get();
            if (!result.isSoftDeleted()) { // deleteAt이 null이라면
                result.deleteSoftly(LocalDateTime.now());
//                log.info("\n1. 좋아요 취소 \n");
                targetAlarm.get().deleteSoftly(LocalDateTime.now());
                return "좋아요를 취소했습니다.";

            } else if (result.isSoftDeleted()) { //deleteAt이 null이 아니라면
//                log.info("\n2. 좋아요 다시 누름 \n");
                result.undoDeletion();
                targetAlarm.get().undoDeletion();
                return "좋아요를 눌렀습니다.";
            }
        }
//            log.info("\n3. 좋아요 처음 누름 \n");
            likeRepository.save(new Like(post, user));
            Alarm savedAlarm = alarmRepository.save(Alarm.toEntity(user, post));
            return "좋아요를 눌렀습니다.";
    }

원인 파악

Hibernate: select like0.id as id1_2, like0.created_at as created_2_2, like0.deleted_at as deleted_3_2, like0.last_modified_at as last_mod4_2, like0.post_id as post_id5_2, like0.user_id as user_id6_2 from likes like0 left outer join post post1 on like0.post_id=post1.id left outer join users user2 on like0.userid=user2.id where ( like0.deleted_at is null) and post1.id=? and user2_.id=?

// 이해하는데 필요없는 어노테이션 생략
@Where(clause = "deleted_at is null")
public class Like extends BaseEntity{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_id")
    private User user;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "post_id")
    private Post post;

    public Like(Post post, User user) {
        this.user = user;
        this.post = post;
    }
}

원인은 like를 조회할때 문제가 있었다...
Hibernate가 쿼리를 날릴때 where 조건을 넣었던 것이다.
Like table에 @where 어노테이션을 정의해 두었는데 이것이 문제가 되었던 것이다.

Like를 조회할때 사용하기 위해 선언한 것인데... 확장성을 고려하지 못했던거 같다.

해결방안

@Where 어노테이션을 Repository의 like를 전체조회하는 메소드에 붙였다.

public interface LikeRepository extends JpaRepository<Like, Long> {
    Optional<Like> findByPostIdAndUserId(Long postId, Long userId);
    @Where(clause = "deleted_at is null")

    Long countByPostId(Long postId);
}

그런데 아래와 같은 에러가 다시 발생했다.

위 에러는 Repository에 대한 에러인데 쿼리문의 리턴에 1개가 아니고 2개라는 뜻이다.
@Where(clause = "deleted_at is null")어노테이션이 안붙었기 때문에

likeRepository.findByPostIdAndUserId(post.getId(), user.getId());

메소드를 실행하고 2개가 반환이 되었다.

다른 해결방안

@Query(nativeQuery=true)를 사용하면 @Where의 조건문을 무시할 수 있다고 한다!
바로 적용시켜 보았다.

public interface LikeRepository extends JpaRepository<Like, Long> {
    @Query(value = "SELECT * FROM likes where post_id and user_id", nativeQuery=true)

    Optional<Like> findByPostIdAndUserId(Long postId, Long userId);

    Long countByPostId(Long postId);
}

그리고 깔끔하게 중복처리가 끝난것을 확인했다:)

지금 로직은 likes가 취소되면 좋아요도 취소하는 로직으로 작성했는데, 이부분에 대해서는 어떻게 처리해야할지 앞으로 조금 더 생각해 보아야 겠다.

profile
배우고, 생각하고, 행동해라

0개의 댓글