2009-09-25 26 views
0

我有一個自定義的UserType,它將日期/時間值存儲在TIMESTAMP字段中,並在插入記錄時更新爲當前時間'UTC'或更新。 (此字段不用於版本控制或用於id目的)Hibernate UserType nullSafeSet - 如何知道是否調用插入/更新或選擇

問題是,這個工作原理非常好,但如果您需要運行查詢,此字段是準備好的語句生成時的條件之一,則自定義用戶類型調用nullSafeSet將值設置爲當前時間,以便查詢始終將該條件設置爲當前時間,而不會產生期望的結果。

是否有可能使nullSafeSet知道它被調用的上下文,以便它可以調整它的插入/更新或選擇的行爲。或者也許有另一種方法來做到這一點?

我試過使用<時間戳.../>,但它不寫入UTC值。 (後備數據庫是Derby,它本身並沒有很好地處理時區。)我也嘗試更新replace(...)方法中的值,但這隻適用於實體從會話中分離然後帶回來。從一些代碼中,實體在單個會話上下文中被檢索和更新,所以該字段不會被更新。

是否有可能仍然有自定義用戶類型寫入UTC值,但使用某種生成器來獲取當前日期/時間只有在插入和更新?

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

回答

1

nullSafeSet()被調用時,雙方實體被保存/更新,並在查詢參數進行設置。

你的問題在於「updateToNow」標誌;如果它在給定實體的映射中設置爲true,則您將總是用當前時間戳覆蓋值。刪除,你會沒事的。

如果您始終將時間戳設置爲當前(對於給定列),請考慮在數據庫中執行此操作,並將您的屬性映射爲「生成」。

+0

是的,這似乎是做到這一點的方法,但使用Derby,您需要使用CURRENT_TIMESTAMP或類似的字段。 Derby不支持針對特定時區(數據庫的UTC)的CURRENT_TIMESTAMP,僅針對虛擬機的當前時區,在我的情況下,該時區必須與UTC不同。 – 2009-09-25 04:55:06

+0

那麼,您的其他選擇是在保存時或在適當的監聽器中使用DAO(如果您使用的是JPA/Hibernate實體管理器,則使用'@ PrePersist')。 – ChssPly76 2009-09-25 05:14:37

+0

目前我剛剛完成了DAO中的更新。稍後我可能會重新訪問一個更好的解決方案。我在Google上搜索時看到了@PrePersist,似乎是一種可能的解決方案,但目前我還沒有使用註釋或JPA/HibernateEntityManager,並且需要很長時間才能滿足當前的需求。 – 2009-09-25 05:32:50

相關問題