Apakah ada cara di JPA untuk memetakan kumpulan Enum dalam kelas Entitas? Atau satu-satunya solusi adalah membungkus Enum dengan kelas domain lain dan menggunakannya untuk memetakan koleksi?
@Entity
public class Person {
public enum InterestsEnum {Books, Sport, etc... }
//@???
Collection<InterestsEnum> interests;
}
Saya menggunakan implementasi Hibernate JPA, tapi tentu saja lebih suka implementasi solusi agnostik.
java
jpa
jakarta-ee
Gennady Shumakher
sumber
sumber
Tautan dalam jawaban Andy adalah titik awal yang bagus untuk memetakan koleksi objek "non-Entitas" di JPA 2, tetapi tidak cukup lengkap dalam hal enum pemetaan. Inilah yang saya temukan sebagai gantinya.
@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; }
sumber
@ElementCollection
danCollection<InterestsEnum> interests;
Sisanya berpotensi berguna tetapi tidak perlu. Misalnya@Enumerated(EnumType.STRING)
menempatkan string yang dapat dibaca manusia di database Anda.@Column
'sname
yang tersirat. Saya hanya ingin mengklarifikasi apa yang tersirat ketika @Column dihilangkan. Dan @Enumerated selalu direkomendasikan karena ordinal adalah hal yang buruk untuk dijadikan default. :)@CollectionTable(name="person_interest", joinColumns = {@JoinColumn(name="person_id")})
Saya dapat melakukannya dengan cara sederhana ini:
@ElementCollection(fetch = FetchType.EAGER) Collection<InterestsEnum> interests;
Eager loading diperlukan untuk menghindari kesalahan inisialisasi pemuatan lambat seperti yang dijelaskan di sini .
sumber
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"); } } // Copy everything else from java.util.RegularEnumSet // ... }
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:
java.util.EnumSet
untuk deskripsi)Kekurangan:
RegularEnumSet
danPersistentEnumSet
hampir sama)EnumSet.noneOf(enumType)
diPersistenEnumSet
, mendeklarasikanAccessType.PROPERTY
dan memberikan dua metode akses yang menggunakan refleksi untuk membaca dan menuliselements
bidang@Embeddable
untukPersistentEnumSet
dan drop kelas tambahan (... interests = new PersistentEnumSet<>(InterestsEnum.class);
)@AttributeOverride
, seperti yang diberikan dalam contoh saya, jika Anda memiliki lebih dari satuPersistentEnumSet
entitas Anda (jika tidak, keduanya akan disimpan ke kolom "elemen" yang sama)values()
with refleksi di konstruktor tidak optimal (terutama saat melihat performanya), tetapi dua opsi lainnya juga memiliki kekurangan:EnumSet.getUniverse()
memanfaatkansun.misc
kelassumber
tl; dr Solusi singkatnya adalah sebagai berikut:
@ElementCollection(targetClass = InterestsEnum.class) @CollectionTable @Enumerated(EnumType.STRING) Collection<InterestsEnum> interests;
Jawaban panjangnya adalah dengan penjelasan ini JPA akan membuat satu tabel yang akan menampung daftar InterestsEnum yang menunjuk ke pengenal kelas utama (Person.class dalam hal ini).
@ElementCollections menentukan di mana JPA dapat menemukan informasi tentang Enum
@CollectionTable membuat tabel yang menyimpan hubungan dari Orang ke InterestsEnum
@Enumerated (EnumType.STRING) beri tahu JPA untuk mempertahankan Enum sebagai String, bisa jadi EnumType.ORDINAL
sumber
Koleksi di JPA mengacu pada hubungan satu-ke-banyak atau banyak-ke-banyak dan mereka hanya dapat berisi entitas lain. Maaf, tapi Anda perlu menggabungkan enum tersebut dalam sebuah entitas. Jika Anda memikirkannya, Anda memerlukan semacam bidang ID dan kunci asing untuk menyimpan informasi ini. Itu kecuali Anda melakukan sesuatu yang gila seperti menyimpan daftar yang dipisahkan koma dalam String (jangan lakukan ini!).
sumber