Hibernate的UserType nullSafeSet - 如何知道是否调用插入/更新或选择 [英] Hibernate UserType nullSafeSet - how to know if called for insert/update or select

查看:121
本文介绍了Hibernate的UserType nullSafeSet - 如何知道是否调用插入/更新或选择的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个自定义的UserType,它将日期/时间值存储在TIMESTAMP字段中,并在插入或更新记录时更新为当前时间'UTC'。 (此字段不用于版本控制或id目的。)



问题是,这个工作原理非常好,但如果您需要在该字段为1的情况下运行查询当准备好的语句被创建时,自定义用户类型nullSafeSet被调用,它将该值设置为当前时间,因此查询总是将该条件设置为当前时间,而不会产生期望的结果。



是否可以使nullSafeSet知道它被调用的上下文,以便它可以调整插入/更新或选择的行为。或者也许有另一种方法来做到这一点?



我试过使用< timestamp ... />但它不会以UTC写入值。 (后备数据库是Derby,它本身并没有很好地处理时区。)我也尝试更新replace(...)方法中的值,但这只适用于实体从会话中分离然后带回来。从一些代码中,实体在单个会话上下文中被检索和更新,所以字段不会被更新。



是否有可能仍然有自定义用户类型写入UTC的值,但使用某种生成器来获取当前日期/时间只在插入和更新?

 
封装示例;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.TimeZone;

import org.hibernate.HibernateException;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;
$ b / **
*类 DateTimestampUserType 实现了一个Hibernate
* UserType 允许将 Date
*实例的持久性作为数据库中的TIMESTAMP。
*
*所有日期实例持续存在UTC / GMT时间。
*
这个 UserType 实现还允许在Hibernate配置中指定布尔参数
*'updateToNow'。这个参数
*控制当一个Date
需要被持久时,它是否更新
*到当前时间。这对TimeModified等字段很有用,因为
*不需要调用代码的干预。
* /
public class DateTimestampUserType implements UserType,ParameterizedType {
$ b $ * / *常数* /
private static final String UTC_TZ =GMT;

/ *成员变量* /
private boolean m_updateToNow = false;
$ b / *方法* /
/ *(非Javadoc)
* @see org.hibernate.usertype.ParameterizedType#setParameterValues(java.util.Properties)
* /
public void setParameterValues(Properties parameters){
if(parameters!= null && parameters.containsKey(updateToNow)){
m_updateToNow = Boolean.parseBoolean(parameters.getProperty( updateToNow));


$ b / *(非Javadoc)
* @see org.hibernate.usertype.UserType#assemble(java.io.Serializable,java。 lang.Object)
* /
public Object assemble(Serializable cached,Object owner)throws HibernateException {
return cached;

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
* /
public Object deepCopy(Object object)抛出HibernateException {
if(object == null)return null;
return new Date(((Date)object).getTime());

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#反汇编(java.lang.Object)
* /
public Serializable反汇编(Object value)抛出HibernateException {
return(Serializable)value;

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#equals(java.lang.Object,java.lang.Object)
* /
public boolean equals(Object x,Object y)throws HibernateException {
if(x == y)return true;
if(x == null || y == null)return false;
return x.equals(y);

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
* /
public int hashCode(Object object)throws HibernateException {
return object.hashCode();

$ b / *(非Javadoc)
* @see org.hibernate.usertype.UserType#isMutable()
* /
public boolean isMutable(){
return true;

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet,java.lang.String [] ,java.lang.Object)
* /
public Object nullSafeGet(ResultSet resultSet,String [] names,Object owner)throws HibernateException,SQLException {
Date result = null;
Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ));
Timestamp timeStamp = resultSet.getTimestamp(names [0],cal);

result = new Date(timeStamp.getTime());

返回结果;

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement,java.lang.Object,int )
* /
public void nullSafeSet(PreparedStatement statement,Object value,int index)throws HibernateException,SQLException {
if(m_updateToNow){
value = new Date();
}

Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ));
时间戳x =新时间戳(((日期)值).getTime());
statement.setTimestamp(index,x,cal);

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#replace(java.lang.Object,java.lang.Object,java如果(m_updateToNow){
返回新的Date(););}
* /
public Object Object
} else {
return original;


$ b(非Javadoc)
* @see org.hibernate.usertype.UserType#returnedClass()
* /
public class returnedClass(){
return Date.class;

$ b $ *(非Javadoc)
* @see org.hibernate.usertype.UserType#sqlTypes()
* /
public int [] sqlTypes(){
return new int [] {java.sql.Types.TIMESTAMP};



解决方案

nullSafeSet )在实体被保存/更新以及查询参数必须被设置时被调用。



你的问题在于updateToNow旗;如果它在给定实体的映射中设置为true,那么您将始终覆盖具有当前时间戳的值。如果您始终将时间戳设置为当前(对于给定的列),请考虑在数据库中执行此操作并映射您的属性asgenerated。

I have a custom UserType which stores a date/time value in a TIMESTAMP field and is updated to the current time 'in UTC' when the record is inserted or updated. (This field is not used for versioning or for id purposes.)

The problem is that this works very nicely but if you need to run a query where this field is one of the criteria when the prepared statement is built, the custom user types nullSafeSet is called which sets the value to current time so the query always has that condition set to the current time which doesn't produce the desired results.

Is is possible to make nullSafeSet aware of the context in which it is being called so it can adjust it's behaviour for insert/update or a select. Or perhaps there is another way to do this?

I have tried using a <timestamp ... /> but it doesn't write the value in UTC. (The backing database is Derby which doesn't deal with time zones by itself very well.) I have also tried just updating the value in the replace(...) method, but this only works if the entity is detached from the session and then brought back. From some of the code the entity is retrieved and updated all within a single session context so the field doesn't get updated.

Is it possible to still have a custom user type write the value in UTC but use some sort of generator to get the current date/time only on insert and update?

package example;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.util.TimeZone;

import org.hibernate.HibernateException;
import org.hibernate.usertype.ParameterizedType;
import org.hibernate.usertype.UserType;

/**
 * The class DateTimestampUserType implements a Hibernate 
 * UserType to allow the persistence of Date 
 * instances as a TIMESTAMP in the database.
 * 
 * All Date instances persisted are in UTC/GMT time.  
 * 
 * This UserType implementation also allows for a boolean parameter
 * 'updateToNow' specified as part of Hibernate configuration. This parameter
 * controls whether when a Date needs to be persisted it is updated 
 * to the current time.  This is useful for fields like TimeModified as it 
 * requires no intervention by the calling code.
 */
public class DateTimestampUserType implements UserType, ParameterizedType {

   /* Constants */
   private static final String UTC_TZ = "GMT";

   /* Member Variables */
   private boolean m_updateToNow = false;

   /* Methods */
   /* (non-Javadoc)
    * @see org.hibernate.usertype.ParameterizedType#setParameterValues(java.util.Properties)
    */
   public void setParameterValues(Properties parameters) {
      if (parameters != null && parameters.containsKey("updateToNow")) {
         m_updateToNow = Boolean.parseBoolean(parameters.getProperty("updateToNow"));
      }
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#assemble(java.io.Serializable, java.lang.Object)
    */
   public Object assemble(Serializable cached, Object owner) throws HibernateException {
      return cached;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object)
    */
   public Object deepCopy(Object object) throws HibernateException {
      if (object == null) return null;
      return new Date(((Date)object).getTime());
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object)
    */
   public Serializable disassemble(Object value) throws HibernateException {
      return (Serializable) value;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#equals(java.lang.Object, java.lang.Object)
    */
   public boolean equals(Object x, Object y) throws HibernateException {
      if (x == y) return true;
      if (x == null || y == null) return false;
      return x.equals(y);
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object)
    */
   public int hashCode(Object object) throws HibernateException {
      return object.hashCode();
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#isMutable()
    */
   public boolean isMutable() {
      return true;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#nullSafeGet(java.sql.ResultSet, java.lang.String[], java.lang.Object)
    */
   public Object nullSafeGet(ResultSet resultSet, String[] names, Object owner) throws HibernateException, SQLException {
      Date result = null;
      Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ));
      Timestamp timeStamp = resultSet.getTimestamp(names[0], cal);

      result = new Date(timeStamp.getTime());

      return result;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#nullSafeSet(java.sql.PreparedStatement, java.lang.Object, int)
    */
   public void nullSafeSet(PreparedStatement statement, Object value, int index) throws HibernateException, SQLException {
      if (m_updateToNow) {
         value = new Date();
      }

      Calendar cal = new GregorianCalendar(TimeZone.getTimeZone(UTC_TZ));
      Timestamp x = new Timestamp(((Date)value).getTime());
      statement.setTimestamp(index, x, cal);
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#replace(java.lang.Object, java.lang.Object, java.lang.Object)
    */
   public Object replace(Object original, Object target, Object owner) throws HibernateException {
      if (m_updateToNow) {
         return new Date();
      } else {
         return original;
      }
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#returnedClass()
    */
   public Class returnedClass() {
      return Date.class;
   }

   /* (non-Javadoc)
    * @see org.hibernate.usertype.UserType#sqlTypes()
    */
   public int[] sqlTypes() {
      return new int[] { java.sql.Types.TIMESTAMP };
   }
}

解决方案

nullSafeSet() is invoked both when the entity is being saved / updated and when query parameter has to be set.

Your problem lies with "updateToNow" flag; if it's set to true in your mapping for given entity, you'll always be overwriting the values with the current timestamp. Remove that and you'll be fine.

If you're always setting the timestamp to current (for given column), consider doing so in the database and mapping your property as "generated" instead.

这篇关于Hibernate的UserType nullSafeSet - 如何知道是否调用插入/更新或选择的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆