@PostMapping("/members/deactivate")
public void deactivate(@RequestBody DeactivateMemberRequest request) {
deactivationService.deactivate(request.getMemberId());
}
@Transactional
public void deactivate(MemberId memberId) {
Member member = memberRepository.findById(memberId).orElseThrow(NoMemberException::new);
member.deactivate(timeProvider.now());
}
@Entity
public class Member extends BaseEntity {
@EmbeddedId
@AttributeOverride(name = "id", column = @Column(name = "id"))
private MemberId id;
private String name;
@Embedded
private Email email;
private String password;
private Boolean isActive;
@ElementCollection
@CollectionTable(
name = "member_deactivation_history",
joinColumns = @JoinColumn(name = "member_id")
)
private final Set<MemberDeactivationHistory> deactivationHistories = new HashSet<>();
// ...
public void deactivate(LocalDateTime deactivatedAt) {
verifyActive();
this.isActive = false;
deactivationHistories.add(new MemberDeactivationHistory(deactivatedAt));
}
// ...
public Set<MemberDeactivationHistory> getDeactivationHistories() {
return deactivationHistories;
}
private void verifyActive() {
if (!isActive) {
throw new IllegalStateException("Not active.");
}
}
}
- member의 deactivate 메소드를 호출하면 밸류 컬렉션에 새로운 deactivationHistory를 추가하기 위해 select 쿼리 호출
밸류는 보통 고유 식별자가 없다고 봐야하기 때문에(고유 식별자를 가진다면 그것은 엔티티라고 봐야하기 때문) 값의 변경이 일어나는 경우 식별자라는 개념이 없기 때문에 원본 데이터를 찾기가 어렵다. 따라서 컬렉션에 변화가 일어나면 전부 지우는 delete 쿼리가 호출되고, 새롭게 모두 다시 insert 한다.
위의 상황은 이미 history가 하나 존재하는 상황에서 다시 한번 member를 비활성화한 것이다.
이처럼 밸류 컬렉션을 사용하게 되면 전부 삭제하고 다시 생성하기 때문에 데이터가 많아진다면 굉장히 비효율적일 수 있다. 개인적으로도 컬렉션을 관리하는 것은 밸류 객체가 아닌 엔티티로 매핑하여 엔티티 관계 애너테이션을 활용하여 설계하는 편이 더 좋은 것 같다.