In hibernate I need to map a Collection of Enums to a single varchar column (e.g. as a comma-separated list of enum values).
To map the Enum to a String database column type, you need to specify the EnumType. STRING value when using the @Enumerated annotation. As expected, the String representation of the Java Enum was used to populate the associated database column value.
By default, when an enum is a part of an entity, JPA maps its values into numbers using the ordinal() method. What it means is that without customizations JPA stores enum value as numbers. These numbers are associated with the order in which you define values in the enum.
1. Introduction In JPA version 2.0 and below, there's no convenient way to map Enum values to a database column. Each option has its limitations and drawbacks. These issues can be avoided by using JPA 2.1. features. In this tutorial, we'll take a look at the different possibilities we have to persist enums in a database using JPA.
With @Enumerated (EnumType.STRING), we can safely add new enum values or change our enum's order. However, renaming an enum value will still break the database data.
Conversions can be configured in OnModelCreating to store the enum values as strings such as "Donkey", "Mule", etc. in the database; you simply need to provide one function which converts from the ModelClrType to the ProviderClrType, and another for the opposite conversion: A null value will never be passed to a value converter.
Also, as we saw, EnumMap is an ordered map, in that its views will iterate in enum order. To get similar behavior for more complex scenarios, we can look at TreeMap or LinkedHashMap. 9. Conclusion In this article, we've explored the EnumMap implementation of the Map interface.
You can create a Hibernate UserType where you set the value as comma separated String:
public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException {
try {
if (null == value) {
st.setNull(index, Types.VARCHAR);
} else {
st.setString(index, toCommaSeparated((Set<Enum>) value));
}
} catch (Exception e) {
throw new HibernateException(String.format("Exception while stringifing '%s'", value), e);
}
}
private String toCommaSeparated(Set<Enum> inputSet) {
StringBuilder sb = new StringBuilder();
String delim = "";
for (Enum current : inputSet) {
sb.append(delim).append(current.name());
delim = ",";
}
return sb.toString();
}
and you get it as an EnumSet:
@Override
public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException {
String name = rs.getString(names[0]);
if (rs.wasNull()) {
return null;
}
try {
Set<Enum<?>> retSet = EnumSet.noneOf(enumClass);
if (StringUtils.isNotBlank(name)) {
String[] values = name.split(",");
for (String value : values) {
Enum<?> current = getEnumValueFor(value);
if (current != null) {
retSet.add(current);
}
}
}
return retSet;
} catch (Exception e) {
throw new HibernateException("Exception getting object from comma separated string", e);
}
}
private Enum<?> getEnumValueFor(String name) {
for (Enum<?> current : enumClass.getEnumConstants()) {
if (current.name().equals(name)) {
return current;
}
}
return null;
}
This implementation is just to give you the idea and it can certainly be improved or adapted to your needs. You can also find plenty of tutorial on how to create your own UserType and probably parametrize it with the Enum class you want to store.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With