2011-03-06 12 views
8

JodaTime DateTime alanlarını JPA ile PostgreSQL'e devam ettirmeye çalışıyorum ancak boş NULL değerleri ile boşluksuz göstergelerle karşılaşıyorum.JPA, PostgreSQL ve NULL değerleri ile JodaTime

NetBeans 7 beta 2 IDE ile çalışıyorum. Kalıcılık uygulaması EclipseLink 2.2.0 ve eşlemenin çalışması için bir EclipseLink Converter kullanıyorum.

@Converter(
    name="dateTimeConverter", 
    converterClass=ejb.util.DateTimeConverter.class 
) 
@Column(columnDefinition="TIMESTAMP WITH TIME ZONE") 
@Convert("dateTimeConverter") 
private DateTime testdate; 

dönüştürücü sınıfı: Bu sürece gerçek bir DateTime seti olmadığı için çalışıyor

public class DateTimeConverter implements Converter { 

    private Logger log; 
    private static final long serialVersionUID = 1L; 

    @Override 
    public Object convertObjectValueToDataValue(Object o, Session sn) { 
     if (o == null) { 
      log.info("convertObjectValueToDataValue returning null"); 
      return null; 
     } 
     return ((DateTime)o).toDate(); 
    } 

    @Override 
    public Object convertDataValueToObjectValue(Object o, Session sn) { 
     if (o == null) { 
      log.info("convertDataValueToObjectValue returning null"); 
      return null; 
     } 
     return new DateTime(o); 
    } 

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

    @Override 
    public void initialize(DatabaseMapping dm, Session sn) { 
     log = Logger.getLogger("ejb.util.DateTimeConverter"); 
    } 

} 

İşte benim alanın ilanıdır. Ama ayarlanmadığı anda EclipseLink bir string tipini kabul ediyor gibi görünüyor ve postgresql, type karakterinin değeri hakkında şikayette bulunmaya başlar. Bunun nedeni, dönüştürücü sınıfının bir tarih nesnesi yerine boş bir gösterici döndürmesi ve EclipseLink'in varsayılan değerlere geri döndüğü varsayılmaktadır.

Düz java.util.Date anahtarına geçiş yapmanın bir yolu var mı?

+1

sınıfında "@ Temporal" açıklamasını eklemeyi denediniz mi? 'Özel DateTime testdate' alanına mı? –

+0

Evet, ancak dağıttığımda, EclipseLink aslında, dönüştürücü nedeniyle @Temporal ek açıklamayı görmezden geleceğine dair bir ileti kaydeder. – Eelke

cevap

7

@Converter kullanıldığında, EclipseLink türü bilmiyor, dolayısıyla başlatmanız gerekiyor. senin initialize(DatabaseMapping dm, Session sn) yöntemde

Eğer

dm.setFieldClassification(java.sql.Date.class); 
// or, dm.setFieldClassification(java.sql.Timestamp.class); 
+0

Makale, setFieldClassification yöntemi netbeans ve docs göre yok, 2.2.0 kullanıyorum. Bu isimde bir alıcı var. Güzel bir çözüm olurdu. – Eelke

+2

Bunu buldu, AbstractDirectMapping alt sınıfında tanımlandı. Yani türü kontrol ettikten ve döküm ettikten sonra, çalışıyor. Teşekkürler. – Eelke

+0

Teşekkürler! Günümü kurtardım :) –

0

Biz farklı bir yaklaşım kullandık, türünü ayarlamak gerekir. (! Bizim kodlama standartları ve özür) POJO olarak

Elimizdeki: package.info olarak

@Column(name="LAST_UPDATED") 
    @Type(type="DateTime") 
    @NotNull 
    public LastUpdType getLastUpdated() 
    { 
    return mLastUpdated; 
    } 

Elimizdeki:

@TypeDefs(
    { 
    @TypeDef(name = "DateTime", typeClass = JodaDateTimeType.class) 
    }) 

Sonra sınıf var JodaDateTimeType

package uk.co.foo.hibernateutils.type; 
import java.io.Serializable; 
import java.sql.PreparedStatement; 
import java.sql.ResultSet; 
import java.sql.SQLException; 
import java.sql.Timestamp; 
import java.sql.Types; 
import org.apache.log4j.Logger; 
import org.hibernate.HibernateException; 
import org.hibernate.cfg.Environment; 
import org.hibernate.usertype.UserType; 
import org.joda.time.DateTime; 


public class JodaDateTimeType implements UserType 
{ 
    private Logger mLogger = Logger.getLogger(getClass()); 

    /** 
    * Implementation taken from org.hibernate.type.MutableType via 
    * org.hibernate.type.CalendarType. 
    * @return true if the field is mutable, false otherwise. 
    * 
    * @see org.hibernate.type.Type#isMutable() 
    */ 
    public boolean isMutable() 
    { 
    return true; 
    } 

    /** 
    * @param aRs A JDBC result set 
    * @param aNames The column names 
    * @param aOwner The containing entity 
    * @return The retrieved value. 
    * @throws HibernateException If a HibernateException occurs. 
    * @throws SQLException If a SQLException occurs. 
    * 
    * @see org.hibernate.usertype.UserType 
    *  #nullSafeGet(java.sql.ResultSet, java.lang.String[], 
    *     java.lang.Object) 
    */ 
    public Object nullSafeGet(ResultSet aRs, String[] aNames, Object aOwner) 
     throws HibernateException, SQLException 
    { 
    return nullSafeGet(aRs, aNames[0]); 
    } 

    /** 
    * Implementation taken mainly from org.hibernate.type.NullableType. 
    * 
    * @param aRs The resultset containing db data. 
    * @param aName The name of the required value. 
    * @return The retrieved value. 
    * @throws HibernateException If a HibernateException occurs. 
    * @throws SQLException If a SQLException occurs. 
    */ 
    public Object nullSafeGet(ResultSet aRs, String aName) 
     throws HibernateException, SQLException 
    { 
    try 
    { 
     Object value = get(aRs, aName); 
     if (value == null || aRs.wasNull()) 
     { 
     if (mLogger.isDebugEnabled()) 
     { 
      mLogger.debug("returning null as column: " + aName); 
     } 
     return null; 
     } 
     else if (mLogger.isDebugEnabled()) 

     { 
     mLogger 
      .debug("returning '" + toString(value) + "' as column: " + aName); 
     } 
     return value; 

    } 
    catch (RuntimeException re) 
    { 
     mLogger.info("could not read column value from result set: " + aName 
     + "; " + re.getMessage()); 
     throw re; 
    } 
    catch (SQLException se) 
    { 
     mLogger.info("could not read column value from result set: " + aName 
     + "; " + se.getMessage()); 
     throw se; 
    } 
    } 

    /** 
    * Implementation mainly taken from org.hibernate.type.CalendarType. 
    * 
    * @param aRs The resultset containing db data. 
    * @param aName The name of the required value. 
    * @return The retrieved value. 
    * @throws HibernateException If a HibernateException occurs. 
    * @throws SQLException If a SQLException occurs. 
    */ 
    protected Object get(ResultSet aRs, String aName) throws HibernateException, 
     SQLException 
    { 
    Timestamp ts = aRs.getTimestamp(aName); 
    if (ts != null) 
    { 
     DateTime dateTime; 
     if (Environment.jvmHasTimestampBug()) 
     { 
     dateTime = new DateTime(ts.getTime() + ts.getNanos()/1000000); 
     } 
     else 
     { 
     dateTime = new DateTime(ts.getTime()); 
     } 
     return dateTime; 
    } 
    return null; 
    } 

    /** 
    * Implementation taken mainly from org.hibernate.type.NullableType. 
    * 
    * @param aSt A JDBC prepared statement 
    * @param aValue The object to write 
    * @param aIndex Statement parameter index 
    * @throws HibernateException If a HibernateException occurs. 
    * @throws SQLException If a SQLException occurs. 
    */ 
    public void nullSafeSet(PreparedStatement aSt, Object aValue, int aIndex) 
     throws HibernateException, SQLException 
    { 
    try 
    { 
     if (aValue == null) 
     { 
     if (mLogger.isDebugEnabled()) 
     { 
      mLogger.debug("binding null to parameter: " + aIndex); 
     } 

     aSt.setNull(aIndex, sqlType()); 
     } 
     else 
     { 
     if (mLogger.isDebugEnabled()) 
     { 
      mLogger.debug("binding '" + toString(aValue) + "' to parameter: " 
      + aIndex); 
     } 

     set(aSt, aValue, aIndex); 
     } 
    } 
    catch (RuntimeException re) 
    { 
     mLogger.info("could not bind value '" + nullSafeToString(aValue) 
     + "' to parameter: " + aIndex + "; " + re.getMessage()); 
     throw re; 
    } 
    catch (SQLException se) 
    { 
     mLogger.info("could not bind value '" + nullSafeToString(aValue) 
     + "' to parameter: " + aIndex + "; " + se.getMessage()); 
     throw se; 
    } 
    } 

    /** 
    * Implementation mainly taken from org.hibernate.type.CalendarType. 
    * 
    * @param aSt A JDBC prepared statement 
    * @param aValue The object to write 
    * @param aIndex Statement parameter index 
    * @throws HibernateException If a HibernateException occurs. 
    * @throws SQLException If a SQLException occurs. 
    */ 
    protected void set(PreparedStatement aSt, Object aValue, int aIndex) 
     throws HibernateException, SQLException 
    { 
    aSt.setTimestamp(aIndex, new Timestamp(((DateTime) aValue).getMillis())); 
    } 

    /** 
    * Implementation mainly taken from org.hibernate.type.NullableType. A 
    * null-safe version of {@link #toString(Object)}. Specifically we are 
    * worried about null safeness in regards to the incoming value parameter, not 
    * the return. 
    * 
    * @param aValue The value to convert to a string representation; may be null. 
    * @return The string representation; may be null. 
    * @throws HibernateException Thrown by {@link #toString(Object)}, which this 
    *   calls. 
    */ 
    private String nullSafeToString(Object aValue) throws HibernateException 
    { 
    if (aValue != null) 
    { 
     return toString(aValue); 
    } 

    return null; 
    } 

    /** 
    * @param aValue value of the correct type. 
    * @return A string representation of the given value. 
    * @throws HibernateException If a HibernateException occurs. 
    */ 
    private String toString(Object aValue) throws HibernateException 
    { 
    return ((DateTime) aValue).toString(); 
    } 

    /** 
    * 
    * @return Types.DATE 
    */ 
    private int sqlType() 
    { 
    return Types.TIMESTAMP; 
    } 

    /** 
    * @return The class returned by nullSafeGet. 
    * @see org.hibernate.usertype.UserType#returnedClass() 
    */ 
    public Class<?> returnedClass() 
    { 
    return DateTime.class; 
    } 

    /** 
    * @param aX First object of type returned by returnedClass. 
    * @param aY Second object of type returned by returnedClass. 
    * @return True if the objects are equal, false otherwise. 
    * @see org.hibernate.usertype.UserType 
    *  #equals(java.lang.Object, java.lang.Object) 
    * @throws HibernateException to conform to superclass signature 
    */ 
    public boolean equals(Object aX, Object aY) throws HibernateException 
    { 
    if (aX == null) 
    { 
     return aY == null; 
    } 

    return aX.equals(aY); 
    } 

    /** 
    * @param aX Object of type returned by returnedClass. 
    * @return Hashcode of given object. 
    * @see org.hibernate.usertype.UserType#hashCode(java.lang.Object) 
    * @throws HibernateException to conform to superclass signature 
    */ 
    public int hashCode(Object aX) throws HibernateException 
    { 
    if (aX == null) 
    { 
     return -1; 
    } 

    return aX.hashCode(); 
    } 

    /** 
    * @return The sql typecodes. 
    * @see org.hibernate.usertype.UserType#sqlTypes() 
    */ 
    public int[] sqlTypes() 
    { 
    return new int[] {sqlType()}; 
    } 

    /** 
    * Implementation taken from 
    * org.springframework.orm.hibernate3.support.AbstractLobType. 
    * @param aCached The object to be cached. 
    * @param aOwner The owner of the cached object. 
    * @return A reconstructed object from the cachable representation. 
    * @throws HibernateException If a HibernateException occurs. 
    * 
    * @see org.hibernate.usertype.UserType 
    *  #assemble(java.io.Serializable, java.lang.Object) 
    */ 
    public Object assemble(Serializable aCached, Object aOwner) 
     throws HibernateException 
    { 
    return aCached; 
    } 

    /** 
    * @param aValue the object to be cloned, which may be null. 
    * @return A copy of the given object. 
    * @see org.hibernate.usertype.UserType#deepCopy(java.lang.Object) 
    * @throws HibernateException to conform to superclass signature 
    */ 
    public Object deepCopy(Object aValue) throws HibernateException 
    { 
    if (aValue != null) 
    { 
     return new DateTime(((DateTime) aValue).getMillis()); 
    } 

    return null; 

    } 

    /** 
    * Implementation taken from 
    * org.springframework.orm.hibernate3.support.AbstractLobType. 
    * @param aValue The object to be cached. 
    * @return A cachable representation of the object. 
    * 
    * @see org.hibernate.usertype.UserType#disassemble(java.lang.Object) 
    * @throws HibernateException to conform to superclass signature 
    */ 
    public Serializable disassemble(Object aValue) throws HibernateException 
    { 
    return (Serializable) aValue; 
    } 

    /** 
    * Implementation taken from 
    * org.springframework.orm.hibernate3.support.AbstractLobType. 
    * @param aOriginal The value from the detached entity being merged 
    * @param aTarget The value in the managed entity 
    * @param aOwner The owner of the cached object. 
    * @return The value to be merged 
    * 
    * @see org.hibernate.usertype.UserType 
    *  #replace(java.lang.Object, java.lang.Object, java.lang.Object) 
    * @throws HibernateException to conform to superclass signature 
    */ 
    public Object replace(Object aOriginal, Object aTarget, Object aOwner) 
     throws HibernateException 
    { 
    return aOriginal; 
    } 
} 
+0

Hazırda bekletme özelliğini kullanmak benim yolumdan biraz uzak ama bunu aklımda tutacağım. Thx – Eelke

+0

Neden kendi türünüzü yazıyorsunuz? Http://joda-time.sourceforge.net/contrib/hibernate/userguide.html –

1

Bu makale: http://www.thoughts-on-java.org/persist-localdate-localdatetime-jpa/ bana oldukça yararlı bir inf verdi o db için localdate devam eden ve DateTimeConverter uygulamasından bazı önemli farklılıklar vardı (özellikle sadece Dönüştürücü'nün değil sadece Dönüştürücünün ve notunun sadece AttributeConverter uygulamasını uygulayarak,

+0

Teşekkür ederiz, iyi görünüyor, cevabınıza biraz daha fazla ayrıntı eklemek veya bir örnek vermek isteyebilirsiniz çünkü cevabınız artık geçerli sadece bir cevap olarak işaretlenmiş olabilir. BTW'nin makaledeki çözümü, aslen soruyu yayınladığımda mevcut olmayan JPA2.1'i gerektirir. – Eelke

+0

Kaynağından kopyalayıp yapıştırmanın 'görgü kurallarından' emin değilim.Çözümünüzün yanlış olduğunu ima etmeyi istemedim (neredeyse 5 yıl önce soruldu! :)). Buradaki ek bilgiyi buraya eklemek istedim, buraya yorumlardan doğru yönde yola çıkan ve daha sonra ek yardıma ihtiyaç duyanlar için. – janoulle