Estou tendo dificuldades para criar uma consulta com HQL, onde é necessário calcular a soma de uma data com um intervalo em meses. A questão é que a quantidade de meses é variável. Sei que no Hibernate cálculos de intervalos de datas não são padronizados (pelo menos foi o que eu li no JIRA do Hibernate), é algo dependente do banco. Pois bem, estou usando postgresql.
Tenho uma classe assim:
@Entity
public class Instrumento {
//...
@Temporal(TemporalType.DATE)
private Date ultimaCalibracao;
@ManyToOne
private TipoInstrumento tipo;
//...
}
E a classe TipoInstrumento é mais ou menos assim
public class TipoInstrumento {
//...
private int periodicidade;
//...
}
Preciso verificar se a ultimaCalibracao, somada ao intervalo em meses da periodicidade é menor que a data atual.
Tentei algo como
from Instrumento i where i.ultimaCalibracao + interval i.tipo.periodicidade 'months' > current_date
[quote=nbluis]Não entendi bem esse hql…
Exemplifique melhor para eu tentar te ajudar…[/quote]
Esqueça esse HQL que eu coloquei, qualquer query que resolva meu problema serve
Tenho um atributo ‘Date ultimaCalibracao’ na classe Instrumento. Essa classe Instrumento possui um atributo da classe TipoInstrumento, a qual por sua vez possui um inteiro ‘periodicidade’.
Preciso retornar todas as instâncias da classe Instrumento cuja soma da ultimaCalibracao com a periodicidade de seu TipoInstrumento seja menor que a data atual
Em pseudo-código seria algo como
Retorne instrumentos onde instrumento.ultimaCalibracao + (instrumento.tipo.periodicidade 'meses') > data atual
select i.* from instrumento i inner join tipoinstrumento ti on i.tipo_id = ti.id where i.ultimacalibracao + interval '1 month' * ti.periodicidade < now();
Agora, passar isso pra HQL que tá difícil de acertar… Como cálculo de intervalo entre datas é dependente do banco, tentei algo como
from Instrumento i where i.ultimaCalibracao + (interval '1 month' * i.tipo.periodicidade) < current_date
Mas recebi o seguinte erro
unexpected token: '1 month' near line 1, column 84
org.hibernate.hql.ast.QuerySyntaxException
int meses = 1;
Calendar auxiliar = Calendar.getInstance(); // cria com a data corrente
auxiliar.add(Calendar.MONTH, meses * (-1));
Date dataMenosMeses = auxiliar.getTime();
Criterion restricao = Restrictions.le("ultimacalibracao", dataMenosMeses);
DetachedCriteria criterio = DetachedCriteria.forClass(Instrumento.class).add(restricao);
int meses = 1;
Calendar auxiliar = Calendar.getInstance(); // cria com a data corrente
auxiliar.add(Calendar.MONTH, meses * (-1));
Date dataMenosMeses = auxiliar.getTime();
Criterion restricao = Restrictions.le("ultimacalibracao", dataMenosMeses);
DetachedCriteria criterio = DetachedCriteria.forClass(Instrumento.class).add(restricao);[/quote]
Olá,
Não entendi essa parte
auxiliar.add(Calendar.MONTH, meses * (-1));
Porque esse (-1) ?
Outro problema é que eu acho que isso não iria funcionar, pois eu não tenho como saber de antemão esse intervalo de meses que está no atributo periodicidade. Cada instância da classe Instrumento persistida possui uma periodicidade diferente!
entao cara vc vai ter q fazer algo do tipo criando sessao para acessar funçoes especificas do banco de dados entao ficaria algo assi:
ISession _session = NHibernateSessionManager.Current;
IQuery query = m_session.CreateQuery(“SELECT a FROM tb1 as a WHERE datediff(Day, :date, a.BDate) > 0”);
query.SetDateTime(“date”, _someDate);
ow no lugar do datediff vc coloca a funçao q vc fez para realizar o calculo q vc conseguiu direto no postgresql.
[quote=ebarros]entao cara vc vai ter q fazer algo do tipo criando sessao para acessar funçoes especificas do banco de dados entao ficaria algo assi:
ISession _session = NHibernateSessionManager.Current;
IQuery query = m_session.CreateQuery(“SELECT a FROM tb1 as a WHERE datediff(Day, :date, a.BDate) > 0”);
query.SetDateTime(“date”, _someDate);
ow no lugar do datediff vc coloca a funçao q vc fez para realizar o calculo q vc conseguiu direto no postgresql.[/quote]
Dai não vai ser hql… e vai ser dependente de banco…
Com essas condições fica fácil…
[quote=nbluis][quote=ebarros]entao cara vc vai ter q fazer algo do tipo criando sessao para acessar funçoes especificas do banco de dados entao ficaria algo assi:
ISession _session = NHibernateSessionManager.Current;
IQuery query = m_session.CreateQuery(“SELECT a FROM tb1 as a WHERE datediff(Day, :date, a.BDate) > 0”);
query.SetDateTime(“date”, _someDate);
ow no lugar do datediff vc coloca a funçao q vc fez para realizar o calculo q vc conseguiu direto no postgresql.[/quote]
Dai não vai ser hql… e vai ser dependente de banco…
Com essas condições fica fácil…[/quote]
É exatamente o que estou tentando evitar, criar query nativa…
Outro problema é que eu acho que isso não iria funcionar, pois eu não tenho como saber de antemão esse intervalo de meses que está no atributo periodicidade. Cada instância da classe Instrumento persistida possui uma periodicidade diferente!
Obrigado![/quote]
Esse (-1) é que, ao invés de somar um numero de meses da “ultimacalibracao”, subtrai-se esses meses da data corrente.
Só agora observei: a periodicidade varia com o instrumento, né? Neste caso… ainda não sei como implementar no Criteria.
Mas vale a pena dar uma pesquisada. O Criteria é bastante interessante.
"from Instrumento i where (current_date - i.ultimaCalibracao) > (i.tipo.periodicidade * 2592000000)"
considerando que “ultimaCalibracao” seja do tipo TIMESTAMP, 2592000000 (2.592E9) representa um mês em milisegundos, resultado de 1000 * 60 * 60 * 24 * 30
por via das dúvidas, force ser do tipo date:
"from Instrumento i where (current_date - cast(i.ultimaCalibracao, date)) > (i.tipo.periodicidade * 30)"
daí, o resultado para comparação vem em número de dias
[quote=ricardosoares]acho que isso pode funcionar:
"from Instrumento i where (current_date - i.ultimaCalibracao) > (i.tipo.periodicidade * 2592000000)"
2592000000 (2.592E9) representa um mês em milisegundos, resultado de 1000 * 60 * 60 * 24 * 30.[/quote]
Mas e os meses com 31 dias e fevereiro, que pode ter 28 ou 29 dias? Esse critério de vencimento da calibração tem q estar certinho, se errar por um dia, já era…