JPA Consultas e Dicas

11 respostas
J

e ai pessoal
vamos ver se consigo atrair o jakefrog, mas quem quiser ajudar, manda ai a sugestão

vamos lá
tenho uma consulta com vários parâmetros, mas como o nosso amigo ai de cima não recomenda o uso de concatenação de Strings, não sei como fazer
bem, tenho a seguinte situação: em uma tela JSF existe vários campos para pesquisar, mas nenhum campo é obrigatório, mas pelo menus um deve ser preenchido
a ideia original era fazer mais ou menos assim:

//montando a consulta String consulta = "minha consulta"; if (pesquisa.getCampoUm() != null) { consulta = consulta +pesquisa.getCampoUm().toString(); } if (pesquisa.getCampoDois() != null) { consulta = consulta +pesquisa.getCampoDoisr(); } ...... //rodar a consulta

mas não é recomendado, por causa da JPQL Injection
então alguma ideia?

11 Respostas

V

Ola!

Eu faria assim…

//lista dos parametros da pesquisa
Map<String, Object> valores = new HashMap<String, Object>();
 //montando a consulta
String consulta = "minha consulta ";
if (pesquisa.getCampoUm() != null) {
	consulta = consulta + " campoUm = :valor1";
	valores.put("valor1", pesquisa.getCampoUm());
}
if (pesquisa.getCampoDois() != null) {
	consulta = consulta + " campoDois = :valor2";
	valores.put("valor2", pesquisa.getCampoDois());
}

//cria a consulta normal
Query query = createQuery(consulta);
//joga os parametros
for (Entry<String, Object> valor : valores.entrySet()) {
	query.setParameter(valor.getKey(), valor.getValue());
}
//rodar a consulta

Embora a concatenação exista, ela não usa valores externos, apenas variaveis, os parametros continuam sendo preenchidos através do query.setParameter.

J

sem falar que estou usando JPQL e não SQL
mas ainda acho que pode causar uma injeção,
mas por enquanto vai ficando assim,
e eu até que tentei usar o

StringBuffer consulta = new StringBuffer("minha consulta");
        if(pesquisa.getCampoUm() != null){
            consulta.append("and condição like " + "%").append(pesquisa.getCampoUm()).append("%");
        }

mas me deu erro, acho que é por que estou tentando rodar JPQL e HQL numa só,
claro que da problema, mas não sei como é o HQL, só vi esse exemplo no GUJ:

StringBuffer sql = new StringBuffer();  
sql.append("select * from xpto where 1=1")  
     
if(parametro1!=null){    
sql.append(" and parametro1="+parametro1);    
}    
if(parametro2!=null){    
sql.append(" and parametro2="+parametro2);    
}   
  
Query query = entityManager().createQuery(sql.toString());  
                             
objetoRetorno = query.getSingleResult(); | query.getResultList(); //retorna um objeto | uma lista

mas estou usando o EclipseLink, não o Hibernate, então empaquei

H

Opa, muito bom esse blog aí hein?! :lol: :lol: :lol:

Rapaz, eu faço igual ao que o vi-gb falou. E funciona para eclipse link também. [=

R

jaissonduarte:
e ai pessoal
vamos ver se consigo atrair o jakefrog, mas quem quiser ajudar, manda ai a sugestão

Hahahahaa, muito bom! eu li o título e lembrei do blog dele também

J

voltando a esse tópico

como ficaria uma consulta com join?
tipo eu tenho que colocar todos os join na

String consulta = "SELECT d FROM ..... ";
ou eu posso adiciona-los se os campos que precisam dele na:

if (pesquisa.getCampoDois() != null) { consulta = consulta + " campoDois = :valor2"; valores.put("valor2", pesquisa.getCampoDois()); }

:smiley:

J

Ola novamente.
tenho uma duvida quanto ao mostrar, ou seja. Eu já inseri no banco normal, mas como eu faço para retornar esses valores. Por exemplo tenha a classe Documento e Autor nxn, quando eu vou mostrar os dados de documento quero que apareça além dos dados do documento o nome dos autores, bom qualquer coisa posto no fórum.
e minha pergunta de join ainda esta de pé
valeu

J

Olha eu aqui de novo espero não ter que criar nenhum tópico novo para isso

Tenho que fazer uma consulta bem grande tenho as entidades:
Documento:
codigo
titulo
tipo
ano
area(referencia area)
curso(referencia curso)
instituicao(referencia instituicao)

Area:
codigo
area

Curso:
codigo
curso

Instituicao
codigo
nome
sigla

ai eu quis fazer esse método:

public List&lt;Documento&gt; pesquisa(Documento documento) {
        System.out.println("inicia DAO");
        System.out.println("Titulo " + documento.getTitulo());
        System.out.println("Ano " + documento.getAno());
        System.out.println("Tipo " + documento.getTipo());
        List&lt;Documento&gt; resultado = new ArrayList&lt;Documento&gt;();
        Map&lt;String, Object&gt; valores = new HashMap&lt;String, Object&gt;();
        String consulta = "SELECT d FROM Documento d left join fetch d.area left join fetch d.curso left join fetch d.instituicao WHERE ";
        if (documento.getTitulo() != null) {
            consulta = consulta + "d.titulo = :titulo";
            valores.put("titulo", "%" + documento.getTitulo() + "%");
        }
        if (documento.getTipo() != null) {
            consulta = consulta + " OR d.tipo = :tipo";
            valores.put("tipo", documento.getTipo());
        }
        if (documento.getAno() != null) {
            consulta = consulta + " OR d.ano = :ano";
            valores.put("ano", documento.getAno());
        }
       if(documento.getArea() != null){
            consulta = consulta + " OR d.area = :area";
            valores.put("area", documento.getArea());
        }
        if (documento.getCurso().getCurso() != null) {
            consulta = consulta + " OR d.curso = :curso";
            valores.put("curso", documento.getCurso().getCurso());
        }

        if (documento.getInstituicao().getSigla() != null) {
            consulta = consulta + " OR d.instituicao = :sigla";
            valores.put("sigla", documento.getInstituicao().getSigla());
        }
        System.out.println("a consulta: " + consulta);
        try {

            Query query = em.createQuery(consulta);

            for (Entry&lt;String, Object&gt; valor : valores.entrySet()) {
                query.setParameter(valor.getKey(), valor.getValue());
            }
            resultado = query.getResultList();

        } catch (Exception e) {
            System.out.println("erro ao realizar a consulta: " + e.getMessage());
        }
        System.out.println("fim DAO");
        return resultado;
    }

mas quando eu executo da esse erro:

erro ao realizar a consulta: You have attempted to set a value of type class java.lang.String for parameter sigla with expected type of class modelo.Instituicao from query string SELECT d FROM Documento d left join fetch d.area left join fetch d.curso left join fetch d.instituicao WHERE d.titulo = :titulo OR d.tipo = :tipo OR d.ano = :ano OR d.area = :area OR d.curso = :curso OR d.instituicao = :sigla.

creio que o erro esta na minha consulta o que vocês acham?

V

Oi, acho que o erro é pq vc ta passando uma string mas a query ta esperando o objeto instituição, deveria ser assim:

P

E essa maneira de montar a query com ifs está errada. Se titulo for null vais ficar com uma query inválida ( … WHERE OR … )

M

Pessoal, blz !

Aqui, estou com uma duvida relacionada a consultas em JPA implementada com EclipseLink.

Tipo como listo todos objetos do BD sem usar SQL ??? estou fazendo desta forma:

@Override
	public ArrayList<Cliente> getLista() {

		EntityManager em = JpaUtil.getEntityManagerFactory()
				.createEntityManager();
		
		String consulta = "SELECT c FROM Cliente c";
		Query q = em.createQuery(consulta);
		ArrayList<Cliente> lista = new ArrayList<Cliente>(q.getResultList());
		 em.close();
		 GWT.log("servidor Listar");
		 Log.debug("Server Listar");
		return lista;
	}

Mas não queria usar nada de SQL, pois essa é uma das vantagem de utilizar um Framework ORM

Como seria isso ??? Alguém tem alguma dica aí …

R

eu utilizo a forma com a qual o vi-gb propôs, mas tbm tou fazendo uns testes com Criteria do JPA 2 que embora seja verbosa e chata,elimina essa concatenação de strings. Aproveitando o gancho de queries dinâmicas como vocês passam os parâmetros para esse tipo de query, eu estava utilizando a estrategia de passar todos os parametros, ex:

<input type="text" name="nome"/>
<input type="text" name="idade"/>
<input type="submit"/>

resultaria em :

mas assim a cada novo item da buscatenho adicionar um parâmetro e isso me parece gambiarra, vi
alguns exemplos que passam logo o objeto todo para a busca

<input type="text" name="pessoa.nome"/>
<input type="text" name="pessoa.idade"/>
<input type="submit"/>

e pra chamar a consulta

vocês trabalham com a primeira ou com a segunda abordagem?

Criado 17 de maio de 2012
Ultima resposta 14 de mar. de 2014
Respostas 11
Participantes 7