
개발을 진행하던 중 다음과 같은 이슈를 전달 받았다.
다음 포스팅은 이슈 중 두 번째 사항에 집중한다.
(첫 번째 사항은 오타를 낸거였다..)
public class MenuImage extends TimeEntity {
...
}
@Getter
@MappedSuperclass
@EntityListeners(AuditingEntityListener.class)
public abstract class TimeEntity {
@CreatedDate
@Column(updatable = false)
private LocalDataTime createdDate;
@LastModifiedDate
private LocalDateTime updatedDate;
}
현재 메뉴 이미지에는 TimeEntity를 상속하고 있다.
다음처럼 다른 엔티티에서도 사용하는 createdDate는 별도의 엔티티를 생성하여 상속하는 방식으로 사용하면 중복 코드 생성이 되지 않으므로 필요한 엔티티에 붙여 사용하기 편하다.

하지만 현재 메뉴 이미지에는 createdDate는 사용하고 있지만, updatedDate는 사용하고 있지 않다. 그로 인해 에러가 발생했던 것이다.
처음에는 DB에 사용하지 않는 컬럼은 등록해두지 않으면 엔티티에 포함이 되어 있다 하더라도 스킵하고 넘어가는 줄 알았지만, 해당 에러를 통해 결국 조치를 취해야 함을 알게되었다.
직접 인서트 문을 작성하고 확인한 에러는 Unknown Column 에러였다.
해당 에러는 많이 봐서 익숙하다. DB에 'updated_date' 컬럼이 없을 때 발생하는 에러였다.
하지만 나는 메뉴 이미지에는 updated_date를 사용하고 싶지 않다.
그러면 어떻게 해줘야 할까?
@MappedSuperclass를 통해 상속 받은 경우나 @Embedded를 통해 다른 객체를 필드에 선언한 경우 다른 컬럼명을 사용할 때 주로 사용하는 JPA 어노테이션이다.
@AttributeOverride(name = "updatedDate", column = @Column(name = "updatedDateDate"))
public class MenuImage extends TimeEntity {
...
}
(메뉴 이미지에서 updatedDate를 사용한다는 가정 하에) updatedDate의 명칭을 updatedDateDate로 변경한다고 하면 다음과 같이 사용해 줄 수 있다.
하지만 우리의 목표는 해당 컬럼을 사용하지 않는 것이다. 다음 작업도 @AttributeOverride를 통해 해결이 가능하다.
@AttributeOverride는 매핑 정보 재정의 어노테이션이다.
name에 해당하는 컬럼에 column에 해당하는 정보를 재정의를 하는 것이다.
그렇다면 어떻게 재정의를 해야 포함이 안될까?
@AttributeOverride(name = "updatedDate", column = @Column(insertable = false, updatable = false))
public class MenuImage extends TimeEntity {
...
}
다음처럼 @Column의 속성 insertable과 updatable의 값을 false로 지정하면 해당 컬럼에 대한 insert, update를 막게된다.
+) 만약 여러 컬럼에 대한 정보를 재정의하고 싶다면 @AttributeOverrides를 사용하면 된다.
현재 updatedDate를 사용하지 않는 엔티티의 개수는 내가 사용하는 것만 해도 대충 5개 정도 된다.
물론 어노테이션 한 줄 복붙이 편하기는 하지만, 어노테이션이 많아져서 정리가 필요할 경우를 대비하여 따로 커스텀 어노테이션으로 나눠볼 생각이다.
(해당 방법이 좋은 방법인지는 잘 모르겠지만 @AttributeOverride라는 긴 내용보다는 짤막하고 한 눈에 보이는 어노테이션이 좋을 것 같다는 판단이었다.)
@AttributeOverride(name = "updatedDate", column = @Column(insertable = false, updatable = false))
public @interface DoNotUseUpdatedDate {
}
@AttributeOverride만을 포함한 커스텀 어노테이션 @DoNotUseUpdatedDate를 제작하여 글로벌 위치에 뒀다.
@DoNotUseUpdatedDate
public class MenuImage extends TimeEntity {
...
}
사용도 간편하게 @DoNotUseUpdatedDate만을 작성하면 되며, 명칭만으로 해당 어노테이션이 어떤 역할을 하는지 알 수 있도록 했다.
(사담) 리팩토링에 도전할 때는 항상 조심스럽다. "코드 한 줄 가지고 너무 생색내는 거 아니냐"라는 반박이 들리면 솔직히 할 말이 없다.
하지만 우리도 편리함을 위해 개발하는 사람이며, 그런 사람으로서 편리함과 간결함을 추구하는 게 헛된 시도라고 생각되지 않는다. 그렇기 때문에 좋은 코드는 아니어도 좋은 시도는 계속 해보고 싶다. 좋은 코드가 되면 더 좋고..
ij