본문 바로가기
이슈와해결

엔티티가 연장되는 속성을 가진 경우 효율적인 참조 관계 맺기

by Renechoi 2023. 12. 14.

개요

댓글에 댓글처럼 어떤 엔티티가 줄을 타고 이어지는 경우가 있다. 사내에서 도메인 서비스를 개발하면서 비슷한 케이스가 있어서 고민해보았었다.

 

예시 서비스는 사용자에게 특정 기능의 연장 기능을 제공한다. 사용자는 해당 기능이 만료되기 일정 기간 전부터 연장을 신청할 수 있으며, 연장 신청 시 새로운 인스턴스가 생성된다. 이 과정에서 새 인스턴스와 이전 연장의 이력 관리가 중요하다.

 

따라서, 이 서비스에 대한 엔티티 설계에서 연장 이력의 연속성을 관리하는 방안에 대한 효율성을 탐구해야 한다.

 

사실 엄청 별거 아니지만 그때 고민한 내용과 생각해보았던 내용들을 간단하게 기록해보았다.

 

  • 실제 용어와 코드는 컨셉으로 대체하였습니다.

 

목차

  • 개요
  • 현재 방식과 문제점
  • 참조 관계를 개선하기
  • 다른 방식은 없을까
  • 결론

 

현재 방식과 문제점

현재 방식은 엔티티에서 특정 필드를 통해 이전 인스턴스와 연결하는 방식이다.

 

public class ServiceFeature {
    private String previousInstanceId;

    private boolean isExtendable;
}

 

이와 같은 방식은 연장 이력의 연속성을 유지하는 데에 직관적이고 효과적이지만, 엔티티들이 계속 연결되면서 발생할 수 있는 성능 문제에 대해서 우려 사항이 있다.

 

참조 관계를 개선하기

기존 extendFrom 필드를 개선하여, 모든 항목들이 원본 항목을 참조하는 구조로 변경했다. 이를 통해, 모든 항목들이 공통된 원본 ID를 공유함으로써, 이력 관리를 효율적으로 할 수 있게 되었다.

 

필드명을 originallyDerivedFrom으로 변경하여, 최초 생성된 항목의 ID를 표시하게 함으로써, 각 항목이 어떤 원본에서 파생되었는지 명확히 한다.

 

@Column(length = 30, columnDefinition = "VARCHAR(30) COMMENT '최초 생성된 항목 아이디'")
private String originallyDerivedFrom;

쿼리 최적화

이와 같이 구현함으로써, originallyDerivedFrom를 기준으로 모든 연장 이력을 조회할 수 있게 된다.

 

originallyDerivedFrom이 NULL이 아닌 경우, 해당 ID를 가진 모든 항목들을 조회할 수 있다. 검색 필터링(예: 시작 및 종료 날짜 기준 검색)과 정렬 로직은 상대적으로 연산 비용이 낮은 어플리케이션의 자원을 사용하여 구현한다.

 

다른 방식은 없을까?

현재의 접근 방식은 항목들이 원본의 ID를 참조하는 것이다. 다른 방식으로, 별도의 테이블을 사용하여 이력을 관리하는 방법도 고려했었다.

 

별도의 이력 테이블 구현

  • 개념: ItemExtensionHistory 같은 새로운 엔티티를 생성하여, 각 항목의 연장 이력을 별도로 기록한다. 이 테이블에는 연장된 항목의 ID, 연장 날짜, 만료 날짜, 연장된 항목의 ID 등을 포함시킬 수 있다.

 

구현 예시

@Entity
public class GenericEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "related_entity_id")
    private String relatedEntityId;

    @Column(name = "history_data", columnDefinition = "json")
    private String historyData; // JSON 형식으로 저장된 이력 데이터
}

 

적용 방안

  • GenericEntity 엔티티가 업데이트될 때마다 GenericEntityHistory 테이블에 새로운 레코드를 추가한다.
  • 이력 조회는 GenericEntityHistory 테이블을 기준으로 하여, 업데이트된 모든 엔티티에 대한 정보를 쉽게 얻는다.

 

이 방식이 좋을 수 있는 포인트

  • 이력의 독립적 관리
  • json 필드를 통한 이력 정보 저장으로 효율적인 데이터 접근

 

결론

  • 데이터 접근이 단순하고 빠른 것이 중요한 경우: 기존 방식(예: originField 사용)이 적합할 것이다.
  • 업데이트 로직이 확장될 가능성이 있는 경우: 미래의 변경사항에 대응하기 위해 별도의 이력 테이블로 관리하는 것이 좋을 수 있다.
  • 당시 프로젝트에서는 후자의 효용성이 크지 않아 첫 번째 방식으로 선택했다.
반응형