Saya menggunakan sedikit modifikasi java.util.RegularEnumSet untuk memiliki EnumSet yang persisten:
@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");
}
}
}
Kelas ini sekarang menjadi basis untuk semua set enum saya:
@Embeddable
public class InterestsSet extends PersistentEnumSet<InterestsEnum> {
public InterestsSet() {
super(InterestsEnum.class);
}
}
Dan set itu dapat saya gunakan di entitas saya:
@Entity
public class MyEntity {
@Embedded
@AttributeOverride(name="elements", column=@Column(name="interests"))
private InterestsSet interests = new InterestsSet();
}
Keuntungan:
- Bekerja dengan jenis enum aman dan berkinerja yang ditetapkan dalam kode Anda (lihat
java.util.EnumSet
untuk deskripsi)
- Set hanya satu kolom numerik dalam database
- semuanya JPA biasa (tidak ada jenis kustom khusus penyedia )
- deklarasi mudah (dan singkat) bidang baru dari jenis yang sama, dibandingkan dengan solusi lain
Kekurangan:
- Duplikasi kode (
RegularEnumSet
dan PersistentEnumSet
hampir sama)
- Anda dapat membungkus hasil
EnumSet.noneOf(enumType)
di PersistenEnumSet
, mendeklarasikan AccessType.PROPERTY
dan memberikan dua metode akses yang menggunakan refleksi untuk membaca dan menulis elements
bidang
- Kelas set tambahan diperlukan untuk setiap kelas enum yang harus disimpan dalam set persisten
- Jika penyedia kegigihan Anda mendukung embeddables tanpa konstruktor publik, Anda bisa menambahkan
@Embeddable
untuk PersistentEnumSet
dan drop kelas tambahan ( ... interests = new PersistentEnumSet<>(InterestsEnum.class);
)
- Anda harus menggunakan
@AttributeOverride
, seperti yang diberikan dalam contoh saya, jika Anda memiliki lebih dari satu PersistentEnumSet
entitas Anda (jika tidak, keduanya akan disimpan ke kolom "elemen" yang sama)
- Akses
values()
with refleksi di konstruktor tidak optimal (terutama saat melihat performanya), tetapi dua opsi lainnya juga memiliki kekurangan:
- Implementasi seperti
EnumSet.getUniverse()
memanfaatkan sun.misc
kelas
- Memberikan nilai array sebagai parameter memiliki risiko bahwa nilai yang diberikan bukan yang benar
- Hanya enum dengan hingga 64 nilai yang didukung (apakah itu benar-benar kekurangan?)
- Anda bisa menggunakan BigInteger sebagai gantinya
- Tidak mudah menggunakan bidang elemen dalam kueri kriteria atau JPQL
- Anda dapat menggunakan operator biner atau kolom bitmask dengan fungsi yang sesuai, jika database Anda mendukungnya