열거 형의 JPA 맵 컬렉션


93

JPA에서 Entity 클래스 내에서 Enum 컬렉션을 매핑하는 방법이 있습니까? 아니면 유일한 해결책은 Enum을 다른 도메인 클래스로 래핑하고 컬렉션을 매핑하는 데 사용하는 것입니까?

@Entity
public class Person {
    public enum InterestsEnum {Books, Sport, etc...  }
    //@???
    Collection<InterestsEnum> interests;
}

Hibernate JPA 구현을 사용하고 있지만 물론 구현에 구애받지 않는 솔루션을 선호합니다.

답변:


112

Hibernate를 사용하면 할 수 있습니다.

@CollectionOfElements(targetElement = InterestsEnum.class)
@JoinTable(name = "tblInterests", joinColumns = @JoinColumn(name = "personID"))
@Column(name = "interest", nullable = false)
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;

141
누군가 지금 이것을 읽으면 ... @CollectionOfElements는 이제 더 이상 사용되지 않습니다. 대신 다음을 사용하십시오. @ElementCollection

2
이 질문의 answser에서 샘플을 찾을 수 있습니다. stackoverflow.com/q/3152787/363573
— Stephan

1
Hibernate에 대해 언급 했으므로이 답변이 공급 업체별로 다를 수 있다고 생각했지만 JoinTable을 사용하면 다른 구현에서 문제가 발생하지 않는 한 그렇지 않다고 생각합니다. 내가 본 것에서 CollectionTable을 대신 사용해야한다고 생각합니다. 그것이 내가 내 대답에서 사용한 것이고 그것은 나를 위해 작동합니다 (예, 나는 또한 지금 Hibernate를 사용하고 있습니다.)
— spaaarky21

나는 이것이 오래된 스레드라는 것을 알고 있지만 우리는 javax.persistence를 사용하여 같은 종류의 것을 구현하고 있습니다. 추가 할 때 : @ElementCollection (targetClass = Roles.class) @CollectionTable (name = "USER_ROLES", joinColumns = @ JoinColumn (name = "USER_ID")) @Column (name = "ROLE", nullable = false) @Enumerated ( EnumType.STRING) 개인 Set <Roles> 역할; User 테이블에는 전체 모델 패키지에서 모든 것이 분리됩니다. User 개체에서 기본 키의 @Id ... @ GeneratedValue 생성기와 첫 번째 @OneToMany의 오류도 빌드시 구피 오류를 발생시킵니다.
— LinuxLars

그만한 가치는-내가보고있는 오류는 버그입니다 -issues.jboss.org/browse/JBIDE-16016
— LinuxLars

65

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;
}

4
안타깝게도 일부 "관리자"는 이유를 밝히지 않고 해당 답변을 삭제하기로 결정했습니다 (여기에서 해당 과정에 대한 내용). 참고로 datanucleus.org/products/accessplatform_3_0/jpa/orm/…
— DataNucleus 2013

2
실제로이 밖으로 필요가있는 것입니다 @ElementCollection그리고 Collection<InterestsEnum> interests; 나머지는 잠재적으로 유용하지만, 필요하지 않습니다. 예를 들어 @Enumerated(EnumType.STRING)사람이 읽을 수있는 문자열을 데이터베이스에 넣습니다.
— CorayThan

2
당신이 맞습니다-이 예에서 당신은 @Column's name가 함축 된 것에 의존 할 수 있습니다. @Column이 생략 될 때 의미하는 바를 명확히하고 싶었습니다. 그리고 @Enumerated는 항상 서수를 기본값으로 사용하는 것이 끔찍한 것이기 때문에 권장됩니다. :)
— spaaarky21

나는 당신이 실제로 person_interest 테이블 필요가 있다고 언급에 그 가치를 생각한다
— lukaszrys가

1
나는 그것을 작동시키기 위해 joinColumn 매개 변수를 추가해야했다@CollectionTable(name="person_interest", joinColumns = {@JoinColumn(name="person_id")})
— Tiago

8

이 간단한 방법으로이 작업을 수행 할 수있었습니다.

@ElementCollection(fetch = FetchType.EAGER)
Collection<InterestsEnum> interests;

여기에 설명 된대로 지연로드 초기화 오류를 방지하려면 즉시로드가 필요 합니다 .


5

영구 EnumSet을 갖도록 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필드
  • 영구 집합에 저장해야하는 모든 열거 형 클래스에는 추가 집합 클래스가 필요합니다.
    • 당신의 지속성 공급자가 public 생성자없이 포함 가능을 지원하는 경우, 당신은 추가 할 수 있습니다 @Embeddable에 PersistentEnumSet(그리고 별도의 클래스를 삭제 ... interests = new PersistentEnumSet<>(InterestsEnum.class);)
  • 엔터티에 @AttributeOverride둘 이상의 항목이있는 경우 내 예제에 제공된대로 를 사용해야합니다 PersistentEnumSet(그렇지 않으면 둘 다 동일한 열 "요소"에 저장 됨).
  • values()생성자에서 with 리플렉션에 액세스하는 것은 최적이 아니지만 (특히 성능을 볼 때) 다른 두 옵션에도 단점이 있습니다.
    • 클래스 EnumSet.getUniverse()사용 과 같은 구현sun.misc
    • 값 배열을 매개 변수로 제공하면 주어진 값이 올바른 값이 아닐 위험이 있습니다.
  • 최대 64 개의 값이있는 열거 형 만 지원됩니다 (정말 단점입니까?).
    • 대신 BigInteger를 사용할 수 있습니다.
  • 기준 쿼리 또는 JPQL에서 요소 필드를 사용하는 것은 쉽지 않습니다.
    • 데이터베이스에서 지원하는 경우 적절한 함수와 함께 이진 연산자 또는 비트 마스크 열을 사용할 수 있습니다.

4

tl; dr 짧은 해결책은 다음과 같습니다.

@ElementCollection(targetClass = InterestsEnum.class)
@CollectionTable
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;

긴 대답은이 주석을 사용하여 JPA가 기본 클래스 식별자 (이 경우에는 Person.class)를 가리키는 InterestsEnum 목록을 보유 할 하나의 테이블을 생성한다는 것입니다.

@ElementCollections는 JPA가 Enum에 대한 정보를 찾을 수있는 위치를 지정합니다.

@CollectionTable은 Person에서 InterestsEnum으로의 관계를 유지하는 테이블을 만듭니다.

@Enumerated (EnumType.STRING)은 JPA에게 Enum을 String으로 유지하도록 지시합니다. EnumType.ORDINAL 일 수 있습니다.


이 경우 변경 불가능한 PersistenceSet으로 저장되기 때문에이 컬렉션을 변경할 수 없습니다.
— Nicolazz92

내 실수. setter로이 세트를 변경할 수 있습니다.
— Nicolazz92

0

JPA의 컬렉션은 일대 다 또는 다 대다 관계를 참조하며 다른 엔터티 만 포함 할 수 있습니다. 죄송합니다. 이러한 열거 형을 엔터티로 래핑해야합니다. 생각해 보면 어쨌든이 정보를 저장하려면 일종의 ID 필드와 외래 키가 필요합니다. 문자열에 쉼표로 구분 된 목록을 저장하는 것과 같은 미친 짓을하지 않는 한 (하지 마십시오!)


8
이것은 JPA 1.0에만 유효합니다. JPA 2.0에서는 위에 표시된대로 @ElementCollection 주석을 사용할 수 있습니다.
— rustyx 2010-12-27
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.