728x90
프로젝트를 진행하던 도중 Repository의 delete 메서드를 타이핑하고 있던 도중 자동 완성으로 두 가지 메서드가 내 눈앞에 등장했다.
해당 메서드들이 매개변수로 원하는 Integer id, Post entity가 둘 다 존재하는 상황이었다.
- 삭제해야 할 Post를 알아야하므로 Post Id를 매개변수로 넘겼기 때문에 Id가 존재했다.
- Post가 있어야 Post를 삭제할 수 있다는 조건을 해결하기 위해 Post Entity를 찾았기 때문에, Entity가 존재했다.
무엇을 선택해야 하는가 생각할 때, id만으로 비교하는 것보다 entity로 비교해서 삭제하는 게 좋지 않을까?라고 단순하게 생각하여 delete를 선택하고 엔티티를 넘겨 삭제 로직을 실행시켰다.
삭제 로직
@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;
private final UserRepository userRepository;
public void deletePost(Integer postId, String userName) {
if (userName == null) {
throw new SNSAppException(NOT_EXIST_TOKEN, NOT_EXIST_TOKEN.getMessage());
}
// user가 찾아지지 않는다면 삭제할 수 없다.
User user = userRepository.findByUserName(userName)
.orElseThrow(
() -> new SNSAppException(USERNAME_NOT_FOUND, USERNAME_NOT_FOUND.getMessage())
);
// post가 찾아지지 않는다면 삭제할 수 없다.
Post post = postRepository.findById(postId)
.orElseThrow(
() -> new SNSAppException(POST_NOT_FOUND, POST_NOT_FOUND.getMessage())
);
// User가 관리자가 아닌데, User와 Post를 작성한 User가 다르면 삭제할 수 없다.
if (!user.getUserRole().equals(ADMIN) && !user.getId().equals(post.getUser().getId())) {
throw new SNSAppException(INVALID_PERMISSION, INVALID_PERMISSION.getMessage());
}
// Post를 찾는 findById 메서드를 사용하였으므로 deleteById가 아닌 Delete 사용.
postRepository.delete(post);
}
}
이후 시간적 여유가 생겨 delete와 deleteById의 차이를 찾아보게 되었다.
SimpleJpaRepository의 delete
@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
...
@Override
@Transactional
@SuppressWarnings("unchecked")
public void delete(T entity) {
Assert.notNull(entity, "Entity must not be null!");
if (entityInformation.isNew(entity)) {
return;
}
Class<?> type = ProxyUtils.getUserClass(entity);
T existing = (T) em.find(type, entityInformation.getId(entity));
// if the entity to be deleted doesn't exist, delete is a NOOP
if (existing == null) {
return;
}
em.remove(em.contains(entity) ? entity : em.merge(entity));
}
}
Delete메서드를 보면 Entity Manager의 remove를 실행시키고 있는 것을 볼 수 있다.
SimpleJpaRepository의 deleteById
@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
...
@Transactional
@Override
public void deleteById(ID id) {
Assert.notNull(id, ID_MUST_NOT_BE_NULL);
delete(findById(id).orElseThrow(() -> new EmptyResultDataAccessException(
String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1)));
}
}
deleteById 메서드를 보면 먼저 findById 메서드를 실행시킨 후 해당 id의 데이터가 존재하면 delete를 진행하는 것을 볼 수 있다.
delete메서드 안에서 findById를 진행하여 원하는 예외를 발생시키는 것 또한 확인할 수 있었다.
결론
두가지 이유 때문에 나는 delete를 사용했다.
- 이미 내 로직 안에 findById로 Post를 찾았다
- 관리자인지, 작성자와 요청자가 동일한 인물인지 확인하는 조건 때문에 delete와 findById를 함께 사용할 수 없다.
만약에 두 가지 이유가 없었다면 내 delete메서드를 다음과 같이 수정하여 사용했을 것 같다.
@Service
@RequiredArgsConstructor
public class PostService {
private final PostRepository postRepository;
private final UserRepository userRepository;
public void deletePost(Integer postId, String userName) {
...
postRepository.delete(
postRepository.findById(postId)
.orElseThrow(
() -> new SNSAppException(POST_NOT_FOUND, POST_NOT_FOUND.getMessage())
)
);
}
}
반응형
'Server > JPA' 카테고리의 다른 글
[JPA] Soft Delete를 위한 @SQLDelete, @Where (0) | 2023.01.06 |
---|---|
[JPA] 01. JPA 시작 (0) | 2022.09.15 |
[JPA] 00. JPA 소개 (0) | 2022.09.14 |