2016-11-15 88 views
0

我上的Java 7和JPA與一個UserType休眠/ JPA實體屬性不正確加載

運行的Hibernate。4.3.11.Final我創建了一個用戶類型編組/解組一個Java枚舉對象數據庫將其存儲爲SMALLINT。

枚舉是地址對象的一個​​屬性,表示地址的一般區域/地點。

我的問題是這樣的:

當我加載地址直接例如爲:

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 

其他標準屬性(具有簡單的列定義註釋)被填充好。

我的區域屬性的註釋是這樣的:

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用戶類型類:

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

} 

在地址表中的區域欄定義爲:

+--------------+-----------------------+------+-----+-------------------+-----------------------------+ 
| Field  | Type     | Null | Key | Default   | Extra      | 
+--------------+-----------------------+------+-----+-------------------+-----------------------------+       | 
| are_id  | smallint(5) unsigned | YES | MUL | NULL          | 
+--------------+-----------------------+------+-----+-------------------+-----------------------------+ 

只是爲了澄清表中的數據。

通過單步執行代碼,似乎在HibernateAreaEnumType中rs.wasNull()返回true,但查看從sql select返回的實際數據(使用p6spy),表明區域枚舉信息存在。

任何幫助非常感激

回答

0

的問題是,我根本不明白ResultSet.wasNull()調用表示什麼。

即它報告最後一列讀取是否具有SQL NULL值。 。

https://docs.oracle.com/javase/7/docs/api/java/sql/ResultSet.html

而且是否有一個空的結果集(這是我以前所認爲

通過undestanding這個我從改變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; 
    } 

然後它工作。