Hibernate自定义类型和JPA2 CriteriaQuery

时间:2014-03-24 03:55:56

标签: hibernate jpa jboss7.x

我们遇到了一个问题,试图将CriteriaBuilder用于自定义类型字段。

下面的示例显示使用自定义@Type注释的birthdate字段。

@Entity
@Table(name = "People")
public class People {
  @Id
  @NotNull
  @Column(name = "id")
  private Integer id;

  @NotNull
  @Size(min = 1, max = 20)
  @Column(name = "Name")
  private String name;

  @NotNull
  @Column(name = "Birthdate")
  @Type(type = "test.MyDateType")
  @Temporal(TemporalType.TIMESTAMP)
  private MyDate birthdate;

  ...

}

MyDateType实现了hibernate的EnhancedUserType

package test;

import java.io.Serializable;
import java.sql.*;
import java.text.*;
import java.util.*;
import java.util.Date;

import org.hibernate.HibernateException;
import org.hibernate.usertype.EnhancedUserType;

import org.hibernate.engine.spi.SessionImplementor;

public class MyDateType implements EnhancedUserType {

  static final ThreadLocal<Calendar> utcCalendar = new ThreadLocal<Calendar>() {
    @Override
    protected Calendar initialValue() {
      return Calendar.getInstance(TimeZone.getTimeZone("GMT"));
    }
  };

  static final ThreadLocal<SimpleDateFormat> utcSimpleDateFormat = new ThreadLocal<SimpleDateFormat>() {
    @Override
    protected SimpleDateFormat initialValue() {
      SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");
      df.setTimeZone(TimeZone.getTimeZone("GMT"));
      return df;
    }
  };

  private static final int[] SQL_TYPES = {Types.TIMESTAMP};

  @Override
  public int[] sqlTypes() {
    return SQL_TYPES;
  }

  @Override
  public boolean equals(Object o1, Object o2) {
    if(o1 == o2) {
      return true;
    }
    if((o1 == null) || (o2 == null)) {
      return false;
    }
    return o1.equals(o2);
  }

  @Override
  public boolean isMutable() {
    return true;
  }

  @Override
  public Class<?> returnedClass() {
    return objectClass;
  }

  protected Class<?> objectClass = MyDate.class;

  @Override
  public Object deepCopy(Object value) {
    return (value == null) ? null : new MyDate(((Date)value).getTime());
  }

  @Override
  public Object nullSafeGet(ResultSet rs, String[] columns, SessionImplementor si, Object owner) throws HibernateException, SQLException {
    Timestamp ts = rs.getTimestamp(columns[0], utcCalendar.get());
    if(ts != null) {
      return new Date(ts.getTime());
    }
    return null;
  }

  @Override
  public void nullSafeSet(PreparedStatement statement, Object value, int index, SessionImplementor si) throws HibernateException,
    SQLException {
    Object val = value;
    if(!(val instanceof java.sql.Timestamp)) {
      val = (val == null) ? null : new java.sql.Timestamp(((Date)val).getTime());
    }
    statement.setTimestamp(index, (java.sql.Timestamp)val, utcCalendar.get());
  }

  @Override
  public Object assemble(Serializable cached, Object owner) throws HibernateException {
    return deepCopy(cached);
  }

  @Override
  public Serializable disassemble(Object value) throws HibernateException {
    return (Serializable)deepCopy(value);
  }

  @Override
  public int hashCode(Object x) throws HibernateException {
    return x.hashCode();
  }

  @Override
  public Object replace(Object original, Object target, Object owner) throws HibernateException {
    return deepCopy(original);
  }

  @Override
  public Object fromXMLString(String xmlValue) {
    try {
      return new Date(utcSimpleDateFormat.get().parse(xmlValue).getTime());
    } catch(ParseException e) {
      System.out.println(e);
    }
    return xmlValue;
  }

  @Override
  public String objectToSQLString(Object value) {
    return null;
  }

  @Override
  public String toXMLString(Object value) {
    return value.toString();
  }
}

测试时,我们按以下方式创建查询

MyDate start = new MyDate(...);
MyDate end = new MyDate(...):

cq.where(cb.between(root.<MyDate> get("birthdate"), start, end));

TypedQuery<People> q = entityManager.createQuery(cq);

List<People> results = q.getResultList();

在尝试执行查询时获取执行

22:03:44,733 WARN  [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-/0.0.0.0:8080-1) SQL Error: 210, SQLState: S0001
22:03:44,734 ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (http-/0.0.0.0:8080-1) Conversion failed when converting datetime from binary/varbinary string.

我们知道注释有效,因为当我们查询Id时,我们会为birthdate字段获取正确的数据。 当我们构建以下查询时,它也可以正常工作。

MyDate start = new MyDate(...);
MyDate end = new MyDate(...):

TypedQuery<People> q = entityManager.createQuery("select p from people where birthdate >= :start and birthdate <= :end", People.class);
q.setParameter("start", start);
q.setParameter("end", end);

List<People> results = q.getResultList();

使用 CriteriaBuilder CriteriaQuery 构建查询时,我们忽略了什么?

0 个答案:

没有答案