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");
}
}
}
このクラスは、私のすべての列挙型セットのベースになりました。
@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
説明についてはを参照)
- セットは、データベース内の1つの数値列です。
- すべてがプレーンJPAです(プロバイダー固有のカスタムタイプはありません)
- 他のソリューションと比較して、同じタイプの新しいフィールドの簡単な(そして短い)宣言
欠点:
- コードの重複(
RegularEnumSet
およびPersistentEnumSet
ほぼ同じ)
- の結果を
EnumSet.noneOf(enumType)
でラップし、リフレクションを使用してフィールドの読み取りと書き込みを行う2つのアクセスメソッドをPersistenEnumSet
宣言AccessType.PROPERTY
して提供できelements
ます。
- 永続セットに格納する必要があるすべての列挙型クラスには、追加のセットクラスが必要です
- あなたの持続性プロバイダがパブリックコンストラクタなしで埋込み可能をサポートしている場合は、追加することができます
@Embeddable
しPersistentEnumSet
(と余分なクラスをドロップします... interests = new PersistentEnumSet<>(InterestsEnum.class);
)
- エンティティに
@AttributeOverride
複数ある場合は、私の例に示すように、を使用する必要がありPersistentEnumSet
ます(そうでない場合、両方が同じ列「要素」に格納されます)
values()
コンストラクターでのwithリフレクションへのアクセスは最適ではありませんが(特にパフォーマンスを見る場合)、他の2つのオプションにも欠点があります。
- のような実装
EnumSet.getUniverse()
はsun.misc
クラスを利用します
- 値の配列をパラメーターとして指定すると、指定された値が正しくないというリスクがあります
- 最大64個の値を持つ列挙型のみがサポートされます(これは本当に欠点ですか?)
- 条件クエリまたはJPQLで要素フィールドを使用するのは簡単ではありません
- データベースがそれをサポートしている場合は、適切な関数で二項演算子またはビットマスク列を使用できます