UniqueConstraint와 Embedded field
JPA를 이용해 Entity 구성 중 Embedded로 구성된 필드와 함께 Unique 제약조건을 사용해야 하는 상황이 생겼다.
문제 발생
2022-05-07 15:03:12.463 ERROR 9907 --- [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Failed to initialize JPA EntityManagerFactory: Unable to create unique key constraint (work_date, staff_id) on table work: database column 'work_date' not found. Make sure that you use the correct column name which depends on the naming strategy in use (it may not be the same as the property name in the entity, especially for relational types)
@Table(
uniqueConstraints = {
@UniqueConstraint(
name = "work_work_date_staff_id_unique",
columnNames = {"work_date", "staff_id"}
)
}
)
public class Work extends BaseTimeEntity {
...
@Embedded
private WorkTime workTime;
...
}
@Embeddable
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class WorkTime {
@Column(nullable = false)
private LocalDate workDate;
@Column(nullable = false)
private LocalDateTime startDate;
@Column(nullable = false)
private LocalDateTime endDate;
...
}
위와 같이 Work Entity는 @Embedded
를 이용해 필드를 사용하고 있는 WorkTime을 포함하고있다.
기존에 사용하던 방식으로 컬럼명을 스네이크 케이스 케이스로 입력하였고, 위와 같은 문제를 보게 되었다.
해결방법
두 가지 해결 방법을 찾게 되었다.
나는 보통 컬럼명을 카멜케이스로 작성하고, 자동으로 스네이크케이스로 변환하여 테이블에서 이용하는 것으로 사용중이였다.
하지만 Embedded로 받아온 필드의 경우 hibernate는 카멜케이스 그대로를 컬럼에서 찾으려 시도하였기 때문에 나타난 현상이였다.
1. @Embeddable
클래스에 @Column
을 명시 (권장)
첫 번째 방법은 @Embeddable 를 선언한 클래스의 필드에 Column명을 명시하는 것이다.
@Embeddable
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class WorkTime {
@Column(nullable = false, name = "work_date")
private LocalDate workDate;
@Column(nullable = false, name = "start_date")
private LocalDateTime startDate;
@Column(nullable = false, name = "end_date")
private LocalDateTime endDate;
...
}
위와 같이 각 필드마다 @Column(name="")
을 스네이크케이스로 명시하여 하이버네이트가 해당 값이 어떤 컬럼을 향하는지 인지시켜준다.
2. @UniqueConstraint
의 columnNames
을 카멜케이스로 작성 (권장하지 않음)
두번째 방법은 UniqueConstraint에 카멜케이스로 컬럼명을 작성하는 것이다.
@Table(
uniqueConstraints = {
@UniqueConstraint(
name = "work_work_date_staff_id_unique",
columnNames = {"workDate", "staff_id"}
)
}
)
위와 같이 work_date로 작성하던 컬럼명을 workDate로 수정하여 인식을 돕는다.
마침
하지만 나는 1번 방법을 선택하고, 모든 엔티티 필드에 매칭되는 DB 컬럼을 작성하기로 하였다.
이유는 가시성도 있지만, 정해놓은 규칙이 있다면 해당 규칙에 맞게 작성하여야 통일성을 어기지 않을 것이라 생각했다.
'Java & Kotlin > Spring Data' 카테고리의 다른 글
[QueryDSL] 프로젝션 (0) | 2022.05.14 |
---|---|
[QueryDSL] QueryDSL 기본문법 (0) | 2022.05.11 |
[QueryDSL] QueryDSL 시작하기 (0) | 2022.05.10 |
[JPA]영속성 전이 CASCADE (0) | 2022.04.21 |
[MyBatis] 동적쿼리(동적 태그) (0) | 2021.05.13 |
[JSP] MyBatis (0) | 2021.03.15 |