Como realizar operações de data em hibernação
Pergunta
Eu quero executar operações de tempo de dados usando hibernate HQL.
Eu quero somar e subtrair duas datas tão bem quanto eu quiser subtrair 1 ano ou 1 mês a partir de uma determinada data.
Como isso é possível usando HQL em hibernação?
Solução
Veja Realizando Data / Hora Math Em HQL? para um exemplo.
Para usar personalizado sql você deve escreveu um dialeto próprio hibernação e registrar:
registerFunction("weekday",
new SQLFunctionTemplate(Hibernate.INTEGER, "to_char(?1,'D')") );
Outras dicas
Você precisa criar o seu próprio dialeto. Algo como o seguinte:
public class MyDialect extends MySQLInnoDBDialect{
public myDialect() {
super();
registerFunction("date_add_interval", new SQLFunctionTemplate(Hibernate.DATE, "date_add(?1, INTERVAL ?2 ?3)"));
}
}
Em Hibernate / MySQL (pelo menos) Você pode converter de e para um Unix Timestamp. Desde o timestamp unix é um inteiro que você pode adicionar um número inteiro de segundos a ele.
FROM_UNIXTIME(UNIX_TIMESTAMP(date)+ (allowedTimeWindow*86400)) as deadline
Ele tem limitações, mas é muito mais fácil do que as abordagens acima.
Esta é uma questão em aberto no Hibernate. A partir de Hibernate 3.3 não há nenhuma maneira padrão para comparações de data alça puramente em HQL:
https://hibernate.atlassian.net/browse/HHH-2434
Hibernate 4.3 oferece funções para acessar data / hora no HQL que são:
current_timestamp() , current_date() , current_time()
As operações aritméticas podem ser gerenciados por:
SECOND(...) , MINUTE(...) , HOUR(...) , DAY(...) , MONTH(...) , YEAR(...)
Disclaimer: Eu sou um novato Java
Eu era capaz de usar current_date() >= fromDate AND dateadd(day, -1, getdate()) <= toDate
em uma declaração HQL contra um db Sybase no Hibernate 3.5.3, sem registrar quaisquer funções.
Exemplo de Uso de aproximação com dialeto para JPA + Hibernate 4.3.1 + MySQL 5
classe pública SampleMySQL5InnoDBDialect estende org.hibernate.dialect.MySQL5InnoDBDialect {
public SampleMySQL5InnoDBDialect() {
super();
registerFunction("date_sub_days", new SQLFunctionTemplate(StandardBasicTypes.DATE, "date_sub(?1, interval ?2 day)"));
}
, em seguida, para a sua classe com a anotação de mapeamento:
@NamedQuery(name = "SampleEntity.getSampleEntitiesForGapOverlapCalculations", query = "from SampleEntity as se where "
+ "((se.toDate between :startDate and :endDate) or (date_sub_days(se.toDate, se.duration) between :startDate and :endDate)) order by se.toDate asc, se.duration desc")
SampleEntity tem toDate campo do tipo java.sql.Date e duração campo inteiro (duração em dias) e estamos calculando fromDate = toDate - duração e selecionar todas as entidades que têm fromDate ou toDate dentro do intervalo [startDate, endDate] .
Hibernate4.3 fornece funções nativas Datas de acesso / Timestamps e para executar operações arithmatic sobre eles
Aqui é o link para a documentação do que expressões podem ser usadas em HQL. Alguns dos quais eu estou mencionando: Para data de acesso / hora:
current_date(), current_time(), and current_timestamp()
As operações aritméticas podem ser feito seguindo. Estas funções levar tempo como entrada:
second(...), minute(...), hour(...), day(...), month(...), and year(...)
Pode-se obter diferença absoluta de em HQL por
current_timestamp() - dateInstance
onde dateInstance pode ter definição
@Column(name = "updated_at")
@Temporal(TemporalType.TIMESTAMP)
private java.util.Date updatedAt;
O resultado é em 0,1 segundos. Assim, para uma diferença absoluta de 1 segundo, a expressão acima dará resultado como 10.
Assim, uma consulta seria algo como:
select t from Table t where (current_timestamp() - updatedAt)>600
usuários Postgres ...
registerFunction("dateadd", new SQLFunctionTemplate(StandardBasicTypes.DATE, "(?1 + INTERVAL ?2)"));
com SQL uso como:
now() < dateadd(:mydate, '-1 day')