berryberrybin / board-project

0 stars 0 forks source link

soft delete 구현 및 문제점 #12

Open berryberrybin opened 1 year ago

berryberrybin commented 1 year ago

soft delete 구현

@Entity
@Where(clause = "deleted = false")
@SQLDelete(sql = "UPDATE posts SET deleted = true WHERE id = ?")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Posts {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String title;

    @Column(nullable = false)
    private String content;

    @Column(nullable = false)
    private boolean deleted;

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "post", cascade = CascadeType.REMOVE)
    private List<Comments> comments = new ArrayList<>();

    public Posts(String title, String content) {
        this.title = title;
        this.content = content;
    }

    public void delete() {
        this.deleted = true;
    }

    public void addComment(Comments comment) {
        this.comments.add(comment);
    }

}
@Entity
@Where(clause = "deleted = false")
@SQLDelete(sql = "UPDATE comments SET deleted = true WHERE id = ?")
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Comments {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private String content;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    private Posts post;

    @Column(nullable = false)
    private boolean deleted;

    public Comments(String content, Posts post) {
        this.content = content;
        this.post = post;
        this.post.addComment(this);
    }

    public void delete() {
        this.deleted = true;
    }

}
berryberrybin commented 1 year ago

soft delete 문제점

@Test
   void 댓글_삭제_성공() {
    //given
    Board board = new Board("testBoard");
    User user = userRepository.save(new User("testUserNickname", "email", User.Role.USER));
    Post post = postRepository.save(new Post(board, user, "testPostTitle", "testPostContent"));
    Comment commentA = commentRepository.save(new Comment(user, post, "testCommentContentA", null));
    Comment commentB = commentRepository.save(new Comment(user, post, "testCommentContentB", null));

    CommentCommand.DeleteCommentCommand command = CommentCommand.DeleteCommentCommand.builder()
            .userId(user.getId())
            .postId(post.getId())
            .commentId(commentA.getId()).build();

    //when
    commentCommandService.deleteComment(command);
    Optional<Comment> deletedComment = commentRepository.findById(commentA.getId());
    Optional<Comment> notDeletedComment = commentRepository.findById(commentB.getId());

    //then
    assertThat(deletedComment.isPresent()).isEqualTo(false);
    assertThat(notDeletedComment.isPresent()).isEqualTo(true);
}
@Test
    @DisplayName("Shop soft delete")
    public void delete() {
        Shop shop = new Shop("가게이름", "대구광역시");
        Shop savedShop = shopRepository.save(shop);

        assertThat(savedShop.getId()).isNotNull();
        assertThat(savedShop.isDeleted()).isFalse();

        shopRepository.delete(savedShop);
        entityManager.flush();

        Optional<Shop> afterDelete = shopRepository.findById(savedShop.getId());
        assertThat(afterDelete).isNotEmpty();
        assertThat(afterDelete.get().isDeleted()).isTrue();
  }
berryberrybin commented 1 year ago

상속 관계에서 soft delete처리

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn
@SQLDelete(sql = "UPDATE shop SET deleted = true WHERE id = ?")
public abstract class Shop {

}
@Entity
@DiscriminatorValue("C")
@OnDelete(action = OnDeleteAction.CASCADE)
public class Restaurant extends Shop {

}
berryberrybin commented 1 year ago
berryberrybin commented 1 year ago

EntityManager를 통한 soft delete 관련 test 해결

@SpringBootTest
@Transactional
class CommentCommandServiceIntegrationTest {

    @Autowired
    private CommentCommandService commentCommandService;

    @Autowired
    private CommentRepository commentRepository;

    @Autowired
    private PostRepository postRepository;

    @Autowired
    private UserRepository userRepository;

    @PersistenceContext
    EntityManager entityManager;

    @Test
    void 댓글_삭제_성공() {
        //given
        Board board = new Board("testBoard");
        User user = userRepository.save(new User("testUserNickname", "email", User.Role.USER));
        Post post = postRepository.save(new Post(board, user, "testPostTitle", "testPostContent"));
        Comment commentA = commentRepository.save(new Comment(user, post, "testCommentContentA", null));
        Comment commentB = commentRepository.save(new Comment(user, post, "testCommentContentB", null));

        entityManager.persist(board); // 영속성 컨텍스트에 저장
        entityManager.persist(user);
        entityManager.persist(post);
        entityManager.persist(commentA);
        entityManager.persist(commentB);

        CommentCommand.DeleteCommentCommand command = CommentCommand.DeleteCommentCommand.builder()
            .userId(user.getId())
            .postId(post.getId())
            .commentId(commentA.getId()).build();

        //when
        commentCommandService.deleteComment(command);

        entityManager.flush(); // 영속성 컨텍스트에 있는 데이터를 DB로 쿼리 전송
        entityManager.clear(); // 영속성 컨텍스트에 있는 데이터를 제거 
        Optional<Comment> deletedComment = commentRepository.findById(commentA.getId());
        Optional<Comment> notDeletedComment = commentRepository.findById(commentB.getId());

        //then
        assertThat(deletedComment.get().getIsDeleted()).isEqualTo(true);
        assertThat(notDeletedComment.isPresent()).isEqualTo(true);
    }
}

persist, flush, clear 정의 및 이해