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
, EclipseLinkConverter
, 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
Compile Error: Package Javax.Servlet Does Not Exist
Java: Subtract '0' from Char to Get an Int... Why Does This Work
Java's Virtual MAChine's Endianness
Download Large File from Server Using Rest Template Java Spring MVC
JSON and Java - Circular Reference
Determine Whether Daylight Savings Time (Dst) Is Active in Java for a Specified Date
How to Get Annotations of a Member Variable
JPA How to Make Composite Foreign Key Part of Composite Primary Key
How to Make Hashmap Work with Arrays as Key
How to Turn Off the Httpsession in Web.Xml
Java Restfull Webservice: Jax-Rs Implementation with Jersey 2.3.1 Libraries