문제
JPA에는 엔티티 클래스 내에서 열거 모음을 매핑하는 방법이 있습니까? 아니면 유일한 해결책은 다른 도메인 클래스로 열거를 래핑하고 컬렉션을 매핑하는 데 사용하는 것입니까?
@Entity
public class Person {
public enum InterestsEnum {Books, Sport, etc... }
//@???
Collection<InterestsEnum> interests;
}
최대 절전 모드 JPA 구현을 사용하고 있지만 물론 구현되지 않은 솔루션을 선호합니다.
해결책
최대 절전 모드를 사용하여 할 수 있습니다
@CollectionOfElements(targetElement = InterestsEnum.class)
@JoinTable(name = "tblInterests", joinColumns = @JoinColumn(name = "personID"))
@Column(name = "interest", nullable = false)
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;
다른 팁
Andy의 답변의 링크는 JPA 2에서 "비 엔티티"객체의 수집을 매핑하기위한 훌륭한 출발점이지만 열거를 매핑 할 때는 완전하지 않습니다. 대신 내가 생각해 낸 것입니다.
@Entity
public class Person {
@ElementCollection(targetClass=InterestsEnum.class)
@Enumerated(EnumType.STRING) // Possibly optional (I'm not sure) but defaults to ORDINAL.
@CollectionTable(name="person_interest")
@Column(name="interest") // Column name in person_interest
Collection<InterestsEnum> interests;
}
나는 이것을 간단한 방식으로 달성 할 수있었습니다.
@ElementCollection(fetch = FetchType.EAGER)
Collection<InterestsEnum> interests;
설명 된대로 게으른 하중을 피하기 위해서는 열망하는 부하가 필요합니다. 여기.
java.util.regularenumset의 약간의 수정을 사용하여 지속적인 열거를 사용하고 있습니다.
@MappedSuperclass
@Access(AccessType.FIELD)
public class PersistentEnumSet<E extends Enum<E>>
extends AbstractSet<E> {
private long elements;
@Transient
private final Class<E> elementType;
@Transient
private final E[] universe;
public PersistentEnumSet(final Class<E> elementType) {
this.elementType = elementType;
try {
this.universe = (E[]) elementType.getMethod("values").invoke(null);
} catch (final ReflectiveOperationException e) {
throw new IllegalArgumentException("Not an enum type: " + elementType, e);
}
if (this.universe.length > 64) {
throw new IllegalArgumentException("More than 64 enum elements are not allowed");
}
}
// Copy everything else from java.util.RegularEnumSet
// ...
}
이 수업은 이제 모든 열거 세트의 기반입니다.
@Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
public InterestsSet() {
super(InterestsEnum.class);
}
}
그리고 내 엔티티에서 사용할 수있는 세트 :
@Entity
public class MyEntity {
// ...
@Embedded
@AttributeOverride(name="elements", column=@Column(name="interests"))
private InterestsSet interests = new InterestsSet();
}
장점 :
- 코드에 세트하는 유형의 안전하고 성능 열거로 작업 (참조
java.util.EnumSet
설명을 위해) - 세트는 데이터베이스에서 하나의 숫자 열입니다.
- 모든 것이 평범한 JPA입니다 (공급자별로 특정 사항 없음 사용자 정의 유형)
- 다른 솔루션과 비교하여 동일한 유형의 새로운 분야의 쉽고 짧은 선언
단점 :
- 코드 복제 (
RegularEnumSet
그리고PersistentEnumSet
거의 동일합니다)- 당신은 결과를 포장 할 수 있습니다
EnumSet.noneOf(enumType)
당신의PersistenEnumSet
, 선언하다AccessType.PROPERTY
반사를 사용하여 읽고 쓰는 두 가지 액세스 방법을 제공합니다.elements
필드
- 당신은 결과를 포장 할 수 있습니다
- 지속적인 세트에 저장 해야하는 모든 열거 클래스에 추가 세트 클래스가 필요합니다.
- 귀하의 지속성 제공 업체가 공개 생성자없이 임베드블을 지원하는 경우 추가 할 수 있습니다.
@Embeddable
에게PersistentEnumSet
추가 클래스를 떨어 뜨립니다 (... interests = new PersistentEnumSet<>(InterestsEnum.class);
)
- 귀하의 지속성 제공 업체가 공개 생성자없이 임베드블을 지원하는 경우 추가 할 수 있습니다.
- 당신은 an을 사용해야합니다
@AttributeOverride
, 내 예에서 주어진대로, 당신이 둘 이상이있는 경우PersistentEnumSet
귀하의 엔티티에서 (그렇지 않으면 둘 다 동일한 열 "요소"에 저장됩니다) - 의 접근
values()
생성자에 반사되는 것은 최적이 아니지만 (특히 성능을 볼 때) 다른 두 옵션에는 단점도 있습니다.- 와 같은 구현
EnumSet.getUniverse()
a를 사용합니다sun.misc
수업 - 매개 변수로 값 배열을 제공하는 것은 주어진 값이 올바른 값이 아닐 위험이 있습니다.
- 와 같은 구현
- 최대 64 개의 값을 가진 열거 만 지원됩니다 (실제로 단점입니까?)
- 대신 BigInteger를 사용할 수 있습니다
- 기준 쿼리 또는 JPQL에서 요소 필드를 사용하기는 쉽지 않습니다.
- 데이터베이스가 지원하는 경우 바이너리 연산자 또는 적절
JPA 컬렉션은 일대일 또는 다수의 관계를 나타내며 다른 엔티티 만 포함 할 수 있습니다. 죄송하지만, 그 열거를 엔티티에 감싸 야합니다. 당신이 그것에 대해 생각한다면, 당신은 어쨌든이 정보를 저장하려면 일종의 ID 필드와 외국 키가 필요합니다. 그것은 당신이 쉼표로 구분 된 목록을 문자열로 보관하는 것과 같은 미친 일을하지 않는 한입니다 (이것을하지 마십시오!).
제휴하지 않습니다 StackOverflow