Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping a Collection of Enums to a single varchar column

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).

like image 502
mjafari Avatar asked Sep 11 '12 13:09

mjafari


People also ask

How do I map an enum to a column in a database?

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.

How are enums stored in database?

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.

How to map enum values to a column in JPA?

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.

Is it possible to change the Order of enum values?

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.

How to convert an enum to a string?

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.

Is EnumMap an ordered map?

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.


1 Answers

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.

like image 158
Andrea Vacondio Avatar answered Oct 29 '22 14:10

Andrea Vacondio