Enums JPA Collection

Is there a way in JPA to map an Enums collection inside an Entity class? Or is the only solution to wrap Enum with another domain class and use it to map the collection?

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

I use the Hibernate JPA implementation, but of course I would prefer the implementation of an agnostic solution.

+64
java java-ee jpa
Jan 06 '09 at 11:40
source share
5 answers

using hibernate you can do

 @CollectionOfElements(targetElement = InterestsEnum.class) @JoinTable(name = "tblInterests", joinColumns = @JoinColumn(name = "personID")) @Column(name = "interest", nullable = false) @Enumerated(EnumType.STRING) Collection<InterestsEnum> interests; 
+84
Mar 13 '09 at 13:50
source share

The link in Andy's answer is a great starting point for matching sets of non-Entity objects in JPA 2, but not quite complete when it comes to displaying enumerations. Here is what I came up with instead.

 @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; } 
+44
Feb 27 '12 at 1:24
source share

I use a small modification of java.util.RegularEnumSet to have a constant 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 // ... } 

This class is now the base for all my enumeration sets:

 @Embeddable public class InterestsSet extends PersistentEnumSet<InterestsEnum> { public InterestsSet() { super(InterestsEnum.class); } } 

And this set that I can use in my essence:

 @Entity public class MyEntity { // ... @Embedded @AttributeOverride(name="elements", column=@Column(name="interests")) private InterestsSet interests = new InterestsSet(); } 

Benefits:

  • Work with the type of safe and executable enumeration installed in your code (see java.util.EnumSet for a description)
  • A collection is just one numeric column in a database
  • everything is just JPA (non-standard user provider types)
  • easy (and short) announcement of new fields of the same type compared to other solutions

Disadvantages:

  • Code duplication ( RegularEnumSet and PersistentEnumSet almost the same)
    • You can wrap the result of EnumSet.noneOf(enumType) in PersistenEnumSet , declare AccessType.PROPERTY and provide two access methods that use reflection to read and write the elements field
  • For each enumeration class to be stored in a persistent set, an additional set class is required
    • If your persistence provider supports embedded attachments without a public constructor, you can add @Embeddable to PersistentEnumSet and remove the extra class ( ... interests = new PersistentEnumSet<>(InterestsEnum.class); )
  • You should use @AttributeOverride as indicated in my example if you have more than one PersistentEnumSet in your entity (otherwise both will be stored in the same column elements)
  • Accessing values() with reflection in the constructor is not optimal (especially when viewing performance), but the other two options have their drawbacks:
    • An implementation similar to EnumSet.getUniverse() uses the sun.misc class
    • Providing an array of values ​​as a parameter has the risk that the given values ​​are not correct
  • Only enumerations with up to 64 values ​​are supported (is this really a flaw?)
    • You can use BigInteger instead
  • It is not easy to use an element field in a query of criteria or in JPQL
    • You can use binary operators or a bitmax column with the corresponding functions if your database supports this
+3
Jan 27 '15 at
source share

Collections in JPA are one-to-many or many-to-many relationships, and they can only contain other objects. Sorry, but you will need to wrap these enumerations in essence. If you think about it, you will need some sort of identifier field and foreign key to save this information anyway. That is, if you are not doing something crazy, how to store a comma-separated list in String (do not do this!).

+1
Jan 06 '09 at 11:52
source share

I was able to accomplish this in a simple way:

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

The desired download is necessary to avoid a lazy boot initialization error, as described here .

+1
Mar 22 '17 at 21:44
source share



All Articles