繁体   English   中英

用户类型未正确加载的Hibernate / JPA实体属性

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM