[英]Hibernate / JPA entity attribute with a UserType not loaded correctly
我正在Java 7和JPA上运行Hibernate 4.3.11.Final
我创建了一个UserType来将Java枚举对象编组/解组到数据库中,并将其作为SMALLINT存储。
枚举是Address对象的属性,代表Address的一般区域/位置。
我的问题是这样的:
当我直接加载地址时,例如:
Address anAddress = session.get(Address.class, 123L);
它加载正常,我可以访问AreaEnum例如
assert anAddress.getArea() != null; // ALL GOOD
但是,当我通过另一个实体的聚合关系访问地址时,AreaEnum未被编组并返回null
,例如
Person aPerson = session.get(Person.class, 5L);
assert aPerson.getAddress().getArea() != null; // FAILS HERE
可以很好地填充其他标准属性(具有简单的列定义批注)。
我对Area属性的注释是这样的:
public class Address {
...
@Type(type = "mls.dao.util.HibernateAreaEnumType")
@Column(name = "are_id", nullable = false, updatable = true, columnDefinition = "SMALLINT")
public AreaEnum getArea() {
return this.area;
}
@Override
public void setArea(AreaEnum _area) {
this.area = _area;
}
...
}
这是HibernateAreaEnumType UserType类:
public class HibernateAreaEnumType implements UserType {
private final Method parseMethod;
private final Class clazz;
public HibernateAreaEnumType() {
clazz = AreaEnum.class;
try {
// this is a static method
this.parseMethod = clazz.getMethod("parseEnum", Long.class);
} catch (Exception e) {
throw new IllegalStateException("issue with trying get the parse method of this enum class: " + clazz.getSimpleName(), e);
}
}
@Override
public Object nullSafeGet(ResultSet _rs, String[] _names, SessionImplementor _sessionImplementor, Object _owner) throws HibernateException, SQLException {
Object result = null;
if (!_rs.wasNull()) {
Long enumId = (long) _rs.getInt(_names[0]);
try {
result = this.parseMethod.invoke(null, enumId);
} catch (Exception e) {
throw new HibernateException("issue trying to method to parse value to make enum: " + enumId, e);
}
}
return result;
}
@Override
public void nullSafeSet(PreparedStatement _ps, Object _value, int _index, SessionImplementor _sessionImplementor) throws HibernateException, SQLException {
try {
if (null == _value) {
_ps.setNull(_index, Types.SMALLINT);
} else {
_ps.setLong(_index, ((MarshallableIdEnum) _value).getId());
}
} catch (ClassCastException e) {
throw new IllegalStateException(this.getClass().getName() + ", issue: " + _value + " / " + _index, e);
}
}
private static final int[] SQL_TYPES = {Types.SMALLINT};
public int[] sqlTypes() {
return SQL_TYPES;
}
public Class returnedClass() {
return this.clazz;
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
@Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
return (x == y) || ((null != x) && (null != y) && x.equals(y));
}
}
地址表中的area列定义为:
+--------------+-----------------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-----------------------+------+-----+-------------------+-----------------------------+ |
| are_id | smallint(5) unsigned | YES | MUL | NULL |
+--------------+-----------------------+------+-----+-------------------+-----------------------------+
只是为了澄清数据在表中。
通过逐步执行代码,似乎在HibernateAreaEnumType中rs.wasNull()
返回的是true
但查看从sql select返回的实际数据(使用p6spy)则显示出了区域枚举信息。
任何帮助真的很感激
问题是我从根本上不了解ResultSet.wasNull()调用指示的内容。
即,它“报告最后读取的列是否具有SQL NULL值”。
https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html
而不是是否有空结果集(这就是我以前的想法。
通过理解这一点,我将nullSafeGet
方法从以下位置更改:
@Override
public Object nullSafeGet(ResultSet _rs, String[] _names, SessionImplementor _sessionImplementor, Object _owner) throws HibernateException, SQLException {
Object result = null;
if (!_rs.wasNull()) {
Long enumId = (long) _rs.getInt(_names[0]);
try {
result = this.parseMethod.invoke(null, enumId);
} catch (Exception e) {
throw new HibernateException("issue trying to method to parse value to make enum: " + enumId, e);
}
}
return result;
}
至
@Override
public Object nullSafeGet(ResultSet _rs, String[] _names, SessionImplementor _sessionImplementor, Object _owner) throws HibernateException, SQLException {
Object result = null;
Short shortId = StandardBasicTypes.SHORT.nullSafeGet(_rs, _names[0], _sessionImplementor);
if (shortId != null) {
log.debug("setting: " + _names[0] + " : " + _rs.wasNull() + " : " + _owner);
Long enumId = shortId.longValue();
try {
result = this.parseMethod.invoke(null, enumId);
} catch (Exception e) {
throw new HibernateException("issue trying to method to parse value to make enum: " + enumId, e);
}
} else {
result = null;
}
return result;
}
然后它起作用了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.