将一组枚举映射到单个varchar列

6
在Hibernate中,我需要将一个枚举集合映射到单个varchar列(例如,作为枚举值的逗号分隔列表)。
2个回答

2

您可以创建一个Hibernate UserType,在其中将值设置为逗号分隔的字符串:

 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();
}

你会得到一个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;
}

这个实现只是为了给你提供想法,肯定可以改进或适应你的需求。你也可以找到很多教程来创建自己的UserType,并且可能使用Enum类对其进行参数化存储。


1

我真的不建议这样做,因为这会使查询数据变得不可能。

如果你真的想这么做,那么只需在setter中将集合转换为字符串,在getter中将字符串转换为枚举集合。使用Guava:

private String fooValues;

public EnumSet<Foo> getFoos() {
    EnumSet<Foo> result = EnumSet.noneOf(Foo.class);
    for (String fooAsString : Splitter.on(',').split(fooValues)) {
        result.add(Foo.valueOf(fooAsString);
    }
    return result;
}

public void setFoos(EnumSet<Foo> foos) {
    this.fooValues = Joiner.on(",").join(foos);
}

谢谢,但我正在寻找一个Hibernate提供的转换工具。 - mjafari
在你的解决方案中,每次调用getter方法都会进行字符串拆分。试图优化性能导致在Set属性和String属性之间同步代码,所有这些都使代码变得混乱不堪。 - mjafari
你找不到这样的东西,因为在单个列中存储一组值是非常丑陋的。将其存储在单独的表中,Hibernate 将会处理一切。 - JB Nizet
1
我倾向于使用这个丑陋的解决方案来避免额外的连接影响性能。 - mjafari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接