Simplificar consulta HQL Hibernate

8 respostas
hibernatejava
jorgereidinaldo

Ola pessoa tenho esta consulta porem ela é um meio estranha e queria retirar ela da minha consulta porem não sei como fazer uma consulta mais simples

Alem que dentro desta consulta a classe ContasReceberRecebidas vem com uma lista e não sei como pegar esta lista na consuta

public ArrayList<LivroReceita> getLivro_Ordem_Servico(String ordemServico,int loja) {
	 final ArrayList<LivroReceita> minhalista = new ArrayList<LivroReceita>();
	 final ArrayList<ContasReceberRecebidas> c_receber = new ArrayList<ContasReceberRecebidas>();
		
		Iterator it;

    	 abrirTransacao();

    	 try {
	 
    	Query query=session.createQuery("From LivroReceita AS livro,"
    			+ "ContasReceberRecebidas as c_receber,"
    			+ "Cliente AS cliente,"
    			+ "Empresa AS empresa,"
    			+ "LocalAtendimento AS localAtendimento,"
    			+ "Venda venda "
    			+ " WHERE   livro.ordemServico= :ordemServico "
    			+ "AND c_receber.fkVenda=livro.fkVenda "
    			+ "AND cliente.idCliente=livro.fkCliente "
    			+ "AND empresa.idLoja=livro.fkLoja "
    			+ "AND venda.fkLocalAtendimento=localAtendimento.idLocalAtendimento "
    			+ "AND venda.idVenda=livro.fkVenda "
    			
    			+ "AND livro.fkLoja= :_empresa "
    			+ "ORDER BY livro.dataEntregaCliente ASC").setParameter("ordemServico", ordemServico).setParameter("_empresa",loja).setMaxResults(1);
    			 it =query.list().iterator();
    	
    			// System.out.println("X14");
    			   fecharTransacao();
      
        while (it.hasNext()){  
        	 LocalAtendimento localAtendimento=new LocalAtendimento();
        	System.out.println("X15 teste");
        	 Object[] bl = (Object[]) it.next();
       LivroReceita livro=(LivroReceita) bl[0] ;
     ArrayList<  ContasReceberRecebidas> c= (ArrayList<ContasReceberRecebidas>) bl[1] ;// esta é a classei que vem com uma lista porem nao sei como pegar os dados 
      // c_receber.add(c);
       Cliente cliente=(Cliente) bl[2];
       Empresa empresa=(Empresa)bl[3];
      localAtendimento=(LocalAtendimento) bl[4];
       Venda venda=(Venda) bl[5];
       
       //livro.setContasReceberRecebidas(c);
      System.out.println(venda.getValorTotalLiquido());
       livro.setCliente(cliente);
       
       livro.setEmpresa(empresa);
       livro.setLocalAtendimento(localAtendimento);
      livro.setVenda(venda);
       
       
       
      
           minhalista.add(livro);
      
        }  
     
    	 
	} catch (Exception e) {
		logger.info("Erro consulta Ordem Servico"+e);
		e.printStackTrace();;
	
	}


    	 
	return minhalista;
}

8 Respostas

Villagram

@jorgereidinaldo
Bom dia campeão.

Tudo depende de como suas entidades estão mapeadas, o próprio hibernate trás todos os registros associados a classe pesquisada.

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "LIVRO_RECEITA")
public class LivroReceita {

    @Id
    private Long id;
    @Column(name = "ORDEM_SERVICO", legth = 100)
    private String ordemServico;
    @Temporal(TemporalType.DATE)
    @Column(name = "DATA_ENTREGA_CLIENTE", columnDefinition = "date")
    private Date dataEntregaCliente;
    @OneToOne
    private Cliente cliente;
    @OneToOne
    private Venda venda;
    @OneToOne
    private Empresa loja;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "livroReceita")
    private List<ContasReceberRecebidas> contasReceberRecebidas;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "CONTAS_RECEBER_RECEBIDAS")
public class ContasReceberRecebidas {

    @Id
    @Column(name = "CONTAS_RECEBER_RECEBIDAS")
    private Long id;
    @ManyToOne
    private LivroReceita livroReceita;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "CLIENTE")
public class Cliente {

    @Id
    @Column(name = "CLIENTE")
    private Long id;
    @Column(name = "NOME")
    private String nome;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "EMPRESA")
public class Empresa {

    @Id
    @Column(name = "EMPRESA")
    private Long id;
    @Column(name = "NOME")
    private String nome;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "LOCAL_ATENDIMENTO")
public class LocalAtendimento {

    @Id
    @Column(name = "LOCAL_ATENDIMENTO")
    private Long id;
    @Column(name = "NOME")
    private String nome;

}

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "VENDA")
public class Venda {

    @Id
    @Column(name = "VENDA")
    private Long id;
    @OneToOne
    private LocalAtendimento localAtendimento;

}

/**
 * "From LivroReceita AS livro,"
 * + "ContasReceberRecebidas as c_receber,"
 * + "Cliente AS cliente,"
 * + "Empresa AS empresa,"
 * + "LocalAtendimento AS localAtendimento,"
 * + "Venda venda "
 * + " WHERE   livro.ordemServico= :ordemServico "
 * + "AND c_receber.fkVenda=livro.fkVenda "
 * + "AND cliente.idCliente=livro.fkCliente "
 * + "AND empresa.idLoja=livro.fkLoja "
 * + "AND venda.fkLocalAtendimento=localAtendimento.idLocalAtendimento "
 * + "AND venda.idVenda=livro.fkVenda "
 * <p>
 * + "AND livro.fkLoja= :_empresa "
 * + "ORDER BY livro.dataEntregaCliente ASC"
 *
 * @param ordemServico
 * @param loja
 * @return
 */
public List<LivroReceita> getLivro_Ordem_Servico(String ordemServico, int loja) {
    Optional<List<LivroReceita>> livroReceitaList = Optional.empty();
    try {
        abrirTransacao();
        
        Query query = session.createQuery("FROM LivroReceita As lv WHERE lv.ordemServico = :ordemServico AND lv.loja.id = :empresa ORDER BY lv.dataEntregaCliente ASC")
                .setParameter("ordemServico", ordemServico)
                .setParameter("empresa", loja)
                .setMaxResults(1);

        livroReceitaList = Optional.ofNullable(query.getResultList());

        fecharTransacao();
    } catch (Exception e) {
        log.info("Erro consulta Ordem Servico" + e);
        e.printStackTrace();
    }
    return livroReceitaList.orElse(new ArrayList());
}

Outra forma é fazer uma pesquisa nativa e colocar tudo o que precisa dentro dela e inserir todos os dados em uma classe especifica.

@Data
@NoArgsConstructor
@AllArgsConstructor
public class LivroReceita {

    private Long id;
    private Long ordemServico;
    private String cliente;
    private Long venda_id;
    private String loja;

}

private Session session;

public List<LivroReceita> getLivro_Ordem_Servico(String ordemServico, int loja) {
    Optional<List<LivroReceita>> livroReceitaList = Optional.empty();
    try {
        abrirTransacao();

        Query query = session.createNativeQuery(
                "SELECT  LV.ID, LV.ORDEM_SERVICO ORDEMSERVICO, CT.NOME CLIENTE, VD.ID VENDA_ID, EP.NOME LOJA"
                        + " FROM LIVRO_RECEIRA LV"
                        + " LEFT JOIN CLIENTE CT ON CT.ID = LV.CLIENTE_ID"
                        + " LEFT JOIN VENDA VD ON VD.ID = LV.VENDA_ID"
                        + " LEFT JOIN EMPRESA EP ON EP.ID = LV.LOJA_ID"
                        + " WHERE"
                        + " LV.ORDEM_SERVICO = ?1 AND LV.LOJA_ID = ?2 ORDER BY LV.DATA_ENTREGA_CLIENTE ASC",
                LivroReceita.class)
                .setParameter(1, ordemServico)
                .setParameter(2, loja)
                .setMaxResults(1);

        livroReceitaList = Optional.ofNullable(query.getResultList());

        fecharTransacao();
    } catch (Exception e) {
        log.info("Erro consulta Ordem Servico" + e);
        e.printStackTrace();
    }
    return livroReceitaList.orElse(new ArrayList());
}
javaflex

Não se complique com HQL. Como colega acima também sugeriu, faça via SQL, é muito mais prático. Joga o resultado da query direto em um DTO.

jorgereidinaldo

obrigado vou comecar a implementar e testar

pmlm

Dizer para não usar Hibernate/HQL é resposta errada sem saber contexto do projeto. Usar nativeQuery no Hibernate é varrer o lixo para debaixo do tapete.
Se as entidades estiverem bem construidas, o HQL simplifica-se naturalmente.

javaflex

Não é errado, é uma opção que pra minha opinião é mais prático. Claro que neste caso nem usaria Hibernate, mas quando pego projeto com ele, passo a usar SQL nessas consultas. Não leve tecnologia como religião. Importante é o resultado. Mas você é livre pra usar essas firulas consulta OO.

Villagram

@jorgereidinaldo
Eu acho que tudo que funciona é válido.

Uso muiiiiiiiito Sql para fazer consultas que levariam horas e muitos recursos de infra para rodar me gerando o problema mais odiado para quem trabalha com POO e JPA que é o famoso overhead.

Em vez de criar vários mapeamentos e depois ficar tratando dados, existem duas maneiras mais simples que diminuem o uso de recursos que são:

1- Criar uma view no banco de dados e um DTO para representar.
2- Fazer uma consulta nativa e usar o DTO para representar.

Pois nem sempre teremos acesso ao banco de dados para fazer modificações e também podemos ter mapeamentos enormes com anos e anos de dados que mesmo usando lazy se tornariam custosos de manipular e penosos em nível de hardware.

Hoje em dia existem tecnologia como o graphQL que resolvem parte do problema, mas ainda assim é necessário fazer várias consultas e filtros para ter um resultado final satisfatório.

Então não adianta ficar vomitando regras, palavras bonitas ou certo e errado. O melhor é aquilo que funciona para a aplicação e contextos onde são necessários.

Para mim o nosso amigo @pmlm está certo em dizer que o HQL simplifica naturalmente, mas também acho que nosso amigo @javaflex está certo em dizer que nessa situação especifica sem conhecer todo o contexto é muito mais prático o uso do SQL, mas no fim quem decide o que é melhor é o desenvolvedor que conhece sua aplicação melhor que todos nós juntos.

pmlm

Não estou a dizer que não se deve usar SQL. Também já fiz milhares de queries SQL e continuo fazendo. Simplesmente a resposta para um problema de HQL não pode ser “largue o hibernate e use SQL” - isso sim é errado.

javaflex

Não é errado, voce não manda em ninguem aqui, talvez só na sua equipe. Pode não ser a sua sugestão, mas é uma opção de melhoria para simplificar consultas, além diminuir overhead. Já melhorei sistemas retirando esses overheads, além de tornar muito mais prático e eficiente o desenvolvimento de consultas, sem se preocupar com modelos genéricos OO complexos, que além disso evita que uma coisa impacte a outra, isso melhorou demais também, cada consulta com seu DTO sem misturas que impactam outras.

Criado 7 de abril de 2020
Ultima resposta 9 de abr. de 2020
Respostas 8
Participantes 4