Как отобразить тип Interval в Hibernate? - PullRequest
10 голосов
/ 22 декабря 2009

В PostgreSQL я использую PersistentDuration для отображения между интервалом и продолжительностью типа sql, но это не работает.

Другой пользователь обнаружил ту же проблему и пришел со своим собственным классом:

public void nullSafeSet(PreparedStatement statement, Object value, int index) 
        throws HibernateException, SQLException { 
    if (value == null) { 
        statement.setNull(index, Types.OTHER); 
    } else { 
        Long interval = ((Long) value).longValue(); 
        Long hours = interval / 3600; 
        Long minutes = (interval - (hours * 3600)) / 60; 
        Long secondes = interval - (hours * 3600) - minutes * 60; 
            statement.setString(index, "'"+ hours +":" 
                    + intervalFormat.format(minutes) + ":" 
                    + intervalFormat.format(secondes)+"'"); 

    } 
}

Но это не работает с реальным форматом, потому что предполагается, что шаблон интервала только «Чч: мм: сс». Дело не в этом: см.

Вот несколько реальных примеров, которые мне нужно проанализировать из базы данных:

1 day 00:29:42
00:29:42
1 week 00:29:42
1 week 2 days  00:29:42
1 month 1 week 2 days  00:29:42
1 year 00:29:42
1 decade 00:29:42

http://www.postgresql.org/docs/current/interactive/datatype-datetime.html

У вас есть чистый раствор?

Ответы [ 4 ]

4 голосов
/ 26 мая 2011

Это рабочее решение для JPA, Hibernate (с аннотациями).

Это начало класса сущности (для таблицы со столбцом Interval):

@Entity
@Table(name="table_with_interval_col")
@TypeDef(name="interval", typeClass = Interval.class)
public class TableWithIntervalCol implements Serializable {

Это столбец интервала:

@Column(name = "interval_col",  nullable = false)
@Type(type = "interval")    
private Integer intervalCol;

А это класс Interval:

package foo.bar.hibernate.type;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Date;

import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
import org.postgresql.util.PGInterval;


/**
 * Postgres Interval type
 * 
 * @author bpgergo
 * 
 */
public class Interval implements UserType {
    private static final int[] SQL_TYPES = { Types.OTHER };

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

    @SuppressWarnings("rawtypes")
    @Override
    public Class returnedClass() {
        return Integer.class;
    }

    @Override
    public boolean equals(Object x, Object y) throws HibernateException {
        return x.equals(y);
    }

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

    @Override
    public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
            throws HibernateException, SQLException {
        String interval = rs.getString(names[0]);
        if (rs.wasNull() || interval == null) {
            return null;
        }
        PGInterval pgInterval = new PGInterval(interval);
        Date epoch = new Date(0l);
        pgInterval.add(epoch);
        return Integer.valueOf((int)epoch.getTime() / 1000);
    }

    public static String getInterval(int value){
        return new PGInterval(0, 0, 0, 0, 0, value).getValue();
    }


    @Override
    public void nullSafeSet(PreparedStatement st, Object value, int index)
            throws HibernateException, SQLException {
        if (value == null) {
            st.setNull(index, Types.VARCHAR);
        } else {
            //this http://postgresql.1045698.n5.nabble.com/Inserting-Information-in-PostgreSQL-interval-td2175203.html#a2175205
            st.setObject(index, getInterval(((Integer) value).intValue()), Types.OTHER);
        }
    }

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

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

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

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

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

}
2 голосов
/ 07 августа 2013

Почему бы просто не превратить его в число и сопоставить с длинным?

SELECT EXTRACT(epoch FROM my_interval)
1 голос
/ 11 ноября 2011

PostgreSQL имеет функцию date_part / extract, которую вы можете использовать для возврата различных полей, причем эпоха является одним из них. При извлечении эпохи из интервала вы получаете количество секунд, содержащихся в интервале, и оттуда вы можете конвертировать по своему усмотрению. Я потерял свой опыт работы с Hibernate, но вы можете сделать это следующим образом:

SELECT
    average_interval_between_airings
  , date_part('epoch', average_interval_between_airings) / 60 as minutes
  , date_part('epoch', average_interval_between_airings) as seconds
FROM shows;
0 голосов
/ 22 декабря 2009

По ссылке у вас должен быть день, а затем часы: минуты: секунды. Таким образом, изменив код на что-то вроде следующего, предполагая, что вам никогда не понадобится больше 23 часов 59 минут в интервале.

statement.setString(index, "'0 "+ hours +":" 
+ intervalFormat.format(minutes) + ":" 
+ intervalFormat.format(secondes)+"'"); 

Я не могу проверить этот код, так как у меня не установлен PostGreSql. Для дальнейшего обсуждения этой же проблемы перейдите по следующей ссылке, хотя вам придется изменить предоставленный код для обработки секунд. Хотя это не должно быть большой проблемой.

https://forum.hibernate.org/viewtopic.php?p=2348558&sid=95488ce561e7efec8a2950f76ae4741c

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...