使用 Hibernate 的不区分大小写的枚举映射
Case insensitive Enum-Mapping with Hibernate
我得到了一个包含 state 列的实体。存储在数据库中的状态是活动的和非活动的(以及更多)。我给自己写了一个枚举,如下所示
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]
是否可以对枚举进行不区分大小写的休眠映射?
您可以将枚举映射为带休眠注释的 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
我遇到了类似的问题,找到了简单的答案。
您可以这样做:
@Column(name = "my_type")
@ColumnTransformer(read = "UPPER(my_type)", write = "LOWER(?)")
@Enumerated(EnumType.STRING)
private MyType type;
(你不需要 @ColumnTransformer
中的 "write" - 对我来说这是为了向后兼容,因为我的行只有小写字母。如果没有 write
Hibernate 将写入枚举与枚举常量中的代码相同的情况)
我得到了一个包含 state 列的实体。存储在数据库中的状态是活动的和非活动的(以及更多)。我给自己写了一个枚举,如下所示
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]
是否可以对枚举进行不区分大小写的休眠映射?
您可以将枚举映射为带休眠注释的 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
我遇到了类似的问题,找到了简单的答案。
您可以这样做:
@Column(name = "my_type")
@ColumnTransformer(read = "UPPER(my_type)", write = "LOWER(?)")
@Enumerated(EnumType.STRING)
private MyType type;
(你不需要 @ColumnTransformer
中的 "write" - 对我来说这是为了向后兼容,因为我的行只有小写字母。如果没有 write
Hibernate 将写入枚举与枚举常量中的代码相同的情况)