我有一个列州的实体。存储在DB中的状态是活动的和非活动的(还有一些)。我给自己写了一个类似下面的枚举
public enum State {
ACTIVE("active"), INACTIVE("inactive");
private String state;
private State(String state) {
this.state = state;
}
}
该实体看起来像:
@Entity
@Table(name = "TEST_DB")
public class MyEntity implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "ID")
private Integer id;
@Enumerated(EnumType.STRING)
@Column(name = "STATE", nullable = false)
private Integer state;
// constructor, getter, setter
}
不幸的是我收到以下错误消息:
javax.ejb.EJBTransactionRolledbackException: Unknown name value [active] for enum class [state]
是否可以对枚举进行不区分大小写的hibernate映射?
答案 0 :(得分:4)
您可以使用hibernate注释将枚举映射为ORDINAL或STRING,例如:
@Enumerated(EnumType.ORDINAL)
private State state;
序数映射将枚举的序号位置放在数据库中。如果更改代码中枚举值的顺序,则会与现有数据库状态冲突。字符串映射将枚举的大写名称放在数据库中。如果重命名枚举值,则会遇到同样的问题。
如果要定义自定义映射(如上面的代码),可以创建org.hibernate.usertype.UserType
的实现,该实现明确映射枚举。
首先,我建议对您的枚举进行一些更改,以便做出以下可能的操作:
public enum State {
ACTIVE("active"), INACTIVE("inactive");
private String stateName;
private State(String stateName) {
this.stateName = stateName;
}
public State forStateName(String stateName) {
for(State state : State.values()) {
if (state.stateName().equals(stateName)) {
return state;
}
}
throw new IllegalArgumentException("Unknown state name " + stateName);
}
public String stateName() {
return stateName;
}
}
这是UserType的简单(!)实现:
public class StateUserType implements UserType {
private static final int[] SQL_TYPES = {Types.VARCHAR};
public int[] sqlTypes() {
return SQL_TYPES;
}
public Class returnedClass() {
return State.class;
}
public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
String stateName = resultSet.getString(names[0]);
State result = null;
if (!resultSet.wasNull()) {
result = State.forStateName(stateName);
}
return result;
}
public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index) throws HibernateException, SQLException {
if (null == value) {
preparedStatement.setNull(index, Types.VARCHAR);
} else {
preparedStatement.setString(index, ((State)value).stateName());
}
}
public Object deepCopy(Object value) throws HibernateException{
return value;
}
public boolean isMutable() {
return false;
}
public Object assemble(Serializable cached, Object owner) throws HibernateException
return cached;
}
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable)value;
}
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
public boolean equals(Object x, Object y) throws HibernateException {
if (x == y) {
return true;
}
if (null == x || null == y) {
return false;
}
return x.equals(y);
}
}
然后映射将成为:
@Type(type="foo.bar.StateUserType")
private State state;
有关如何实现UserType的另一个示例,请参阅:http://www.gabiaxel.com/2011/01/better-enum-mapping-with-hibernate.html
答案 1 :(得分:1)
我遇到了类似的问题,并找到了简单的答案。
您可以执行以下操作:
@Column(name = "my_type")
@ColumnTransformer(read = "UPPER(my_type)", write = "LOWER(?)")
@Enumerated(EnumType.STRING)
private MyType type;
(您不需要在@ColumnTransformer
中进行“写”-对我来说,这是为了向后兼容,因为我的行只使用小写。如果没有write
,Hibernate将在相同的情况下写枚举,例如在代码中使用枚举常量)