JPAにEntityクラス内のEnumsのコレクションをマップする方法はありますか?または、唯一の解決策は、Enumを別のドメインクラスでラップし、それを使用してコレクションをマップすることですか?
@Entity
public class Person {
public enum InterestsEnum {Books, Sport, etc... }
//@???
Collection<InterestsEnum> interests;
}
私はHibernate JPA実装を使用していますが、もちろん実装に依存しないソリューションを好みます。
あなたができるHibernateを使用して
@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;
here で説明されている遅延読み込みの初期化エラーを回避するために、積極的な読み込みが必要です。
Java.util.RegularEnumSetを少し変更して永続的なEnumSetを使用しています。
_@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
_を参照)欠点:
RegularEnumSet
とPersistentEnumSet
はほぼ同じです)EnumSet.noneOf(enumType)
の結果をPersistenEnumSet
でラップし、_AccessType.PROPERTY
_を宣言し、リフレクションを使用してelements
フィールドを読み書きする2つのアクセス方法を提供できます。PersistentEnumSet
に_@Embeddable
_を追加し、余分なクラス(... interests = new PersistentEnumSet<>(InterestsEnum.class);
)を削除できます。PersistentEnumSet
がある場合は、私の例にあるように_@AttributeOverride
_を使用する必要があります(そうしないと、両方が同じ列「要素」に格納されます)values()
のアクセスは最適ではありません(特にパフォーマンスを見る場合)が、他の2つのオプションにも欠点があります:EnumSet.getUniverse()
のような実装は_Sun.misc
_クラスを利用しますJPAのコレクションは、1対多または多対多の関係を参照し、他のエンティティのみを含むことができます。申し訳ありませんが、これらの列挙型をエンティティでラップする必要があります。考えてみると、とにかくこの情報を保存するために何らかのIDフィールドと外部キーが必要になります。これは、文字列にコンマ区切りのリストを保存するなどのクレイジーなことをしない限りです(これはしないでください!)。