JPA Map Collection of Enums

JPA map collection of Enums

using Hibernate you can do

@ElementCollection(targetElement = InterestsEnum.class)
@JoinTable(name = "tblInterests", joinColumns = @JoinColumn(name = "personID"))
@Column(name = "interest", nullable = false)
@Enumerated(EnumType.STRING)
Collection<InterestsEnum> interests;

How to properly map collection of enums in hibernate?

Alright, I found a not so nice workaround. First of all, I annotated the List<Role> roles; as following:

@ElementCollection(targetClass = Role.class)
@JoinTable(name = "User_Roles", joinColumns = @JoinColumn(name = "userName"))
@Enumerated(EnumType.STRING)
@Column(name = "role")
private List<Role> roles;

My Role enum does not have any annotations.

This setup would normally result in the LazyInitializationException, which I worked around by adding a System.out.println(user); as this does access the roles list (replacing it with a getRoles() resulted in the same exception) directly after fetching the user.

As you can guess, this solution is not really fine/acceptible at all. As long as I don't find a better solution (most probably eager-loading), I will roll with this one.


UPDATE

I actually got it solved. It works now with eager-loading. In fact, the setup remained as posted above in the answer. The IllegalStateException I mentioned in the question, is actually caused by the bug HHH-12594. I simply removed hibernate.default_batch_fetch_size from my configuration and it then worked as intended.

Hibernate map list of enums without jointable

No, with @ElementCollection you have to use @CollectionTable which is a separate database table used just to store your values (actually preferable in this case).

You can have a simple String mapping and a couple of util methods for converting a CSV string to list of enums and vice versa. Something like this

private String myCSVValues;
...
public List<MyEnum> getMyEnums() {
String[] csvs = this.myCSVValues.split(",");
List<MyEnum> myEnums = new ArrayList<MyEnum>();
for (String s : csvs) {
myEnums.add(MyEnum.valueOf(s));
}
return myEnums;
}

public void setMyEnums(List<MyEnum> myEnums) {
this.myCSVValues = org.apache.commons.lang3.StringUtils.join(myEnums, ",");
}

Or, you can try with @Converter to map a List<MyEnum> directly to a varchar column

@Converter(autoApply = true)
public class MyEnumConverter implements AttributeConverter<List<MyEnum>, String> {

@Override
public String convertToDatabaseColumn(List<MyEnum> myEnums) {
...
}

@Override
public List<MyEnum> convertToEntityAttribute(String dbData) {
...
}

}

Jpa repository with list of enum

You don't have sufficient config for Enum persistence, try :

@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "RoomType", joinColumns = @JoinColumn(name = "id"))
@Enumerated(EnumType.STRING)
List<RoomType> chosenRooms

@ElementCollection - Defines a collection of instances of a basic type or embeddable class.
@CollectionTable - pecifies the table that is used for the mapping of collections of basic or embeddable types (name - name of the collection table, joinColumn - The foreign key columns of the collection table).

Enumerated - Specifies that a persistent property or field should be persisted as a enumerated type.

JPA mapping a map where key is an Enum

Kudos to @BilalBOUTAYA

The answer is: use @MapKeyEnumerated.

The @Enumerated annotation applies to the value column which is obviously incompatible with the annotation.

Example:

@JsonIgnore
@ElementCollection(fetch = FetchType.LAZY)
@CollectionTable(name = "FTT_REGISTRI_ESCLUSIONI", foreignKey = @ForeignKey(value = ConstraintMode.CONSTRAINT, name = "FTT_FK_ESCLUSIONE_TO_REGISTRO"), joinColumns = @JoinColumn(name = "REGISTRO_ID"))
@MapKeyColumn(name = "CLAUSOLA_ESCLUSIONE", length = 40, nullable = false)
@MapKeyClass(FttEsclusioneType.class)
@MapKeyEnumerated(EnumType.STRING)
@Column(name = "RECORD_COUNT", nullable = false)
protected final Map<FttEsclusioneType, Long> esclusioneRecordCounters = new HashMap<>();

Map enum in JPA with fixed values?

For versions earlier than JPA 2.1, JPA provides only two ways to deal with enums, by their name or by their ordinal. And the standard JPA doesn't support custom types. So:

  • If you want to do custom type conversions, you'll have to use a provider extension (with Hibernate UserType, EclipseLink Converter, etc). (the second solution). ~or~
  • You'll have to use the @PrePersist and @PostLoad trick (the first solution). ~or~
  • Annotate getter and setter taking and returning the int value ~or~
  • Use an integer attribute at the entity level and perform a translation in getters and setters.

I'll illustrate the latest option (this is a basic implementation, tweak it as required):

@Entity
@Table(name = "AUTHORITY_")
public class Authority implements Serializable {

public enum Right {
READ(100), WRITE(200), EDITOR (300);

private int value;

Right(int value) { this.value = value; }

public int getValue() { return value; }

public static Right parse(int id) {
Right right = null; // Default
for (Right item : Right.values()) {
if (item.getValue()==id) {
right = item;
break;
}
}
return right;
}

};

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "AUTHORITY_ID")
private Long id;

@Column(name = "RIGHT_ID")
private int rightId;

public Right getRight () {
return Right.parse(this.rightId);
}

public void setRight(Right right) {
this.rightId = right.getValue();
}

}

Hibernate 3.3: how to map list of enums by name

The answer turned out to be a combination of a typedef approach I had previously rejected plus an inclusion of a missing dependency.

I had not realized that org.hibernate.type.EnumType is defined in the Hibernate Annotations JAR, so I added

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-annotations</artifactId>
<version>${hibernate.version}</version>
</dependency>

to my POM.

Then, I reworked my Hibernate configuration to use a typedef to map my enum through this type:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<typedef name="TheValue" class="org.hibernate.type.EnumType">
<param name="enumClass">com.example.TheValue</param>
<param name="type">12</param>
</typedef>
<class name="com.example.TheEntity" table="entityTable" lazy="false">
<list name="theValues" table="theValueMapping">
<key column="entity" />
<list-index column="listIndex" />
<element
column="value"
length="4"
type="TheValue"
not-null="true"
/>
</list>
</class>
</hibernate-mapping>

My thanks to grimarr from the Hibernate forums for showing that I needed hibernate-annotations.jar and to Mike from SO for showing that the typedef approach should work.

JPA and a set of enum values

Just use:

List<MediaRole.MediaRoleEnum> mediaRoles;
Set<MediaRole.MediaRoleEnum> mediaRoles;

depending on your needs. Check Which Java Type do you use for JPA collections and why?

In the mapping file:

<attributes>
<element-collection name="mediaRoles"/>
</attributes>

If you use annotations, just use the equivalent one:

@ElementCollection
List<MediaRole.MediaRoleEnum> mediaRoles;


Related Topics



Leave a reply



Submit