Problema com HQL - Hibernate

5 respostas
N

Gente,

quero fazer uma consulta usando HQL do Hibernate. Quero consultar um aluno por determinado curso e cep, sendo que eu posso passar como parâmetros da consulta o nome do curso ou o cep ou ambos. Montei meu método de consulta assim:

@Repository
public class CursoRepositoryJpaImpl implements CursoRepository {

    @PersistenceContext
    private EntityManager entityManager;

    @Override
    public Curso consultarAlunoPorNomeDoCursoEhCepAluno(String nomeCurso, String cepAluno) {
		
		String consulta = "select curso from Curso as curso left join fetch curso.alunos as aluno join fetch aluno.endereco as endereco " +
		"where curso.nome = coalesce (:nomeCurso, curso.nome) " +
		"and endereco.cep = coalesce (:cepAluno, endereco.cep)";							
		
		Query query = entityManager.createQuery(consulta);
		query.setParameter("nomeCurso", nomeCurso);
		query.setParameter("cepAluno", cepAluno);
		
		try {
		    return (Curso) query.getSingleResult();
		} catch (NoResultException nre) {
		    throw new NoResultException("Curso não encontrado");
		} catch (NonUniqueResultException nre) {
		    throw new NonUniqueResultException("Retornou mais de um elemento");
		}

	}

}

E funciona quando eu passo apenas o cep ou quando eu passo ambos, nome do curso e cep do Aluno. O problema é quando eu passo somente o nome do curso. A consulta não me retorna nada. O interessante é que nesta condição, se eu tirar esta linha "and endereco.cep = coalesce (:cepAluno, endereco.cep)", ou seja, não passar o parâmetro cep=null, a consulta traz o resultado. O SQL que é montado está correto. Não sei porque nesta condição não funciona. Alguém já passou por algo parecido e saberia me explicar o que está havendo? Obrigado!

// Entidades

@Entity
@Table(name="CURSO")
public class Curso {

     @Id
     @Column(name="SEQ_CURSO", nullable=false)
     @GeneratedValue(generator="curso_generator", strategy=GenerationType.SEQUENCE)
     @SequenceGenerator(name="curso_generator", sequenceName="SQ_curso",schema = "xxxxx", initialValue=1, allocationSize=1)
     private Integer sequencial;

     @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="curso")
     private List<Aluno> alunos;
     
     @Column(name="NOME", nullable=false)
     private String nome;

     //gets and sets
} 

@Entity
@Table(name="ALUNO")
public class Aluno {

     @Id
     @Column(name="SEQ_ALUNO", nullable=false)
     @GeneratedValue(generator="aluno_generator", strategy=GenerationType.SEQUENCE)
     @SequenceGenerator(name="aluno_generator", sequenceName="SQ_ALUNO",schema = "xxxxx", initialValue=1, allocationSize=1)
     private Integer sequencial;
     
     @JoinColumn(name="SEQ_CURSO", referencedColumnName="SEQ_CURSO")
     @ManyToOne(optional = false, fetch=FetchType.LAZY)
     private Curso curso;
     
     @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="aluno")
     private Endereco endereco;

     //gets and sets
}

@Entity
@Table(name="ENDERECO")
public class Endereco {

     @Id
     @Column(name="SEQ_ENDERECO", nullable=false)
     @GeneratedValue(generator="endereco_generator", strategy=GenerationType.SEQUENCE)
     @SequenceGenerator(name="endereco_generator", sequenceName="SQ_ENDERECO",schema = "xxxxx", initialValue=1, allocationSize=1)
     private Integer sequencial;

     @OneToOne(fetch=FetchType.LAZY, optional=true)
     @JoinColumn(name="SEQ_ALUNO")
     private Aluno aluno;
     
     @Column(name="CEP")
     private String cep;
    
     //gets and sets
}

5 Respostas

A

Tenta colocar:
“and endereco.cep = coalesce (:cepAluno, aluno.endereco.cep)”

N

arthurgon:
Tenta colocar:
“and endereco.cep = coalesce (:cepAluno, aluno.endereco.cep)”

Oi, arthurgon. Eu fiz desse jeito e não funcionou. :frowning:

Veja uma coisa interessante:

Assim funciona:

String consulta = "select curso from Curso as curso left join fetch curso.alunos as aluno join fetch aluno.endereco as endereco " +  
        "where curso.nome = coalesce (:nomeCurso, curso.nome) " +  
        "and endereco.cep = coalesce (null, endereco.cep)";                              
          
        Query query = entityManager.createQuery(consulta);  
        query.setParameter("nomeCurso", nomeCurso);  
      //  query.setParameter("cepAluno", cepAluno);

Mas assim não funciona:

String consulta = "select curso from Curso as curso left join fetch curso.alunos as aluno join fetch aluno.endereco as endereco " +  
        "where curso.nome = coalesce (:nomeCurso, curso.nome) " +  
        "and endereco.cep = coalesce (:cepAluno, endereco.cep)";                              
          
        Query query = entityManager.createQuery(consulta);  
        query.setParameter("nomeCurso", nomeCurso);  
        query.setParameter("cepAluno", null);
E

Amigo, bom dia.

tente desta forma com Criteria…

public  Aluno consultarAlunoPorNomeDoCursoEhCepAluno(String nomeCurso, String cep){

		Criteria crit = entityManager.createCriteria(consulta);		
		Disjunction or = Restrictions.disjunction();
		
		if(nomeCurso != null){
			or.add( Restrictions.eq("curso.nome", nomeCurso) );
		}
		
		if(cepAluno != null){
			or.add( Restrictions.eq("endereco.cep", cep) );
		}		
		
       crit.add(or);
	
	return crit.uniqueResult();
	
	}

na sua classe Aluno tem um Curso e um Endereco
então, vc consegue navegar nos seus objetos atraves dos atributos

endereco.cep ou curso.nome

Assim vc consegue passar o um parametro por vez ou os dois.

N

Oi, edu2306

Obrigado pela atenção. Eu comecei agora com Hibernate e não possuo muito conhecimento. Eu criei um HQL dinâmico como você sugeriu abaixo, formando a query conforme os parâmetros que não estão nulo e está funcionando, porém, gostaria de saber porque não funciona do jeito que eu postei aqui. Será um bug do Hibernate ou estou fazendo algo errado?

E

Funcionaria se não fosse dinamico.

ou vc teria que ficar se preocupando com concatenação de String.

se não fosse dinamico funcionaria.

Com o Hibernate vc navega pelos seu objetos, então o seu HQL ficaria assim.

String consulta = "select Aluno a where a.curso.nome = :nomeCurso and a.endereco.cep = :cep"

Query query = entityManager.createQuery(consulta);    
        query.setParameter("nomeCurso", nomeCurso); 
        query.setParameter("cep", cep);

que bom que conseguiu!

Criado 11 de outubro de 2011
Ultima resposta 11 de out. de 2011
Respostas 5
Participantes 3