1
resposta

Como funciona as projections? ficou pouco claro e ruim os exemplos.

Minha dúvida é como funciona as projections no exemplo dado, usando uma query native parece que nada indica a entidade original. Seria apenas a ordem da query?

Outro comentário , mais do que uma questão, é que esse assunto de Projections poderia ser mais extenso e explicado com exemplos melhores, eu fiz uma pesquisa agora tentando achar essa resposta e as formas mais comuns de Projections não são baseadas em Native Queries mas sim várias outras como View de entidades ou DTOs, entre outras.

Eu ainda não achei a resposta mas acho que valeria fazer mais exemplos para projections e DTOs pois parece algo bastante utilizado no dia a dia. Existem projections de entidades relacionadas também? Seria interessante exemplos de como explorar caso por exemplo precisamos apenas o nome do Cargo e sálario, como ficaria?

Obrigado!

1 resposta

As projections sao interfaces que voce cria para pegar os atributos de queries nativas. elas serao o espelho do nome do campo que voce atribui na query nativa. tem que ser o mesmo nome se nao da errado. eu coloco elas na mesma ordem que defini no select.

Eu acho elas mais praticas do que o DTO, pois eu nao consigo fazer o parse do dto direto da query nativa. eu uso dto em jpq mas tem que colocar o construtor do dto tipo

@Query("select new br.com.app.dto.CarroDTO(c.id,c.modelo,c.cor) from Carro c ")
public List<CarroDTO> pesquisaCarroResumido();

ja a projections eu acho mais simples

public interface CarroProjection {
    public Long getId();

    public String getModelo();

    public String getCor();
}
@Query("select id,modelo,cor from carro", nativeQuery=true)
public List<CarroProjection> pesquisaCarroResumido();

Esse é um exemplo simples. Que nao precisaria de uma projection mas tem selects nativos que com jpql voce nao conseguiria resolver, ai fica melhor usar uma projection para facilitar os dados. Ai voce usa um modelmapper da vida ou faz um construtor no dto que recebe a projection e faz a conversao. ou passa a projection direto para o controller que ele devolve o json dela. tipo assim

@Query(value = "select i.idproduto as idProduto,p.ean as codigoEan,pp.idfamilia as idProdutoEquivalente, p.descricao,n.loja as idLoja,pe.estoque_atual as estoque,i.custoant as precoCustoAnterior," 
            + "case i.cst_icms when '20' then round(i.valorunitario * ((100-pt.pis-pt.cofins-(i.tributacao*((100-i.reducaoicms)/100)))/100),2)" 
            + "when '00' then round(i.valorunitario * ((100-pt.pis-pt.cofins-(i.tributacao*((100-i.reducaoicms)/100)))/100)\n,2)" 
            + "else round(i.valorunitario * ((100-pt.pis-pt.cofins)/100),2) end as precoCusto,"
            + "pp.venda1 as precoVenda, if(curdate() >= pp.dtiniciopromo and curdate() <= pp.dtfinalpromo, pp.prpromocao, 0.00) as precoPromocao,"
            + "case i.cst_icms when '20' then round(i.valorunitario * ((100-pt.pis-pt.cofins-(i.tributacao*((100-i.reducaoicms)/100)))/100)/((100-pt.icms-pt.pis-pt.cofins-pt.fecoep)/100),2)" 
            + "when '00' then round(i.valorunitario * ((100-pt.pis-pt.cofins-(i.tributacao*((100-i.reducaoicms)/100)))/100)/((100-pt.icms-pt.pis-pt.cofins-pt.fecoep)/100),2)"
            + "else round(i.valorunitario * ((100-pt.pis-pt.cofins)/100)/((100-pt.icms-pt.pis-pt.cofins-pt.fecoep)/100),2) end as precoMargemZero,pp.margem as margemLucro" 
            + "from produto_preco pp"
            + "inner join produto_estoque pe on pp.idproduto=pe.idproduto and pe.id_loja=pp.id_loja"
            + "inner join produto_tributacao pt on pp.idproduto=pt.idproduto and pt.id_loja=pp.id_loja"
            + "inner join produto p on pp.idproduto=p.idproduto"
            + "inner join nfentrada n on n.numeronf=pp.pendente_nota and pp.pendente_fornecedor=n.idfornecedor"
            + "inner join itensnfentrada i on n.idnfentrada=i.idnfentrada and pp.idproduto=i.idproduto and pp.id_loja=n.loja"
            + "where pp.pendente='S'" 
            + "and (pp.pendente_nota = :numeroNotaFiscal or :numeroNotaFiscal is null)"
            + "and (pp.data_ult_reajuste between :dataInicial and :dataFinal or :dataInicial is null and :dataFinal is null)"
            + "and (pp.pendente_fornecedor = :idFornecedor or :idFornecedor is null)" 
            + "and (p.idgrupo = :idSecao or :idSecao is null)"
            + "and (p.idsubgrupo = :idCategoria or :idCategoria is null)" 
            + "and (p.idsubgrupo1 = :idFamilia or :idFamilia is null)"
            + "and (p.descricao like concat('%', :descricaoProduto, '%') or :descricaoProduto is null) order by p.descricao", nativeQuery = true)
public List<ProdutoPrecoPendente> pendentePreco(@Param("numeroNotaFiscal") Long numeroNotaFiscal,
        @Param("dataInicial") LocalDate dataInicial, @Param("dataFinal") LocalDate dataFinal,
        @Param("idFornecedor") Long idFornecedor, @Param("idSecao") Long idSecao,
        @Param("idCategoria") Long idCategoria, @Param("idFamilia") Long idFamilia,
        @Param("descricaoProduto") String descricaoProduto);

voltando a sua duvida, o uso de projections ou dtos, sao para simplesmente voce controlar o que voce envia no final das contas para o usuario. num cenario onde voce vai abrir um grid de pesquisa, voce nao precisa fazer um select de toda a tabela que as vezes tem mais de 100 campos. e ainda mais num cenario de API, para evitar o trafego desnecessario de dados. algumas vezes tambem voce nao precisa devolver para a tela os relacionamentos do objeto completo. se voce quiser apenas listar o nome do funcionario e o cargo dele. voce nao precisa do id, do salario, etc... so precisa do nome do funcionario e o nome do cargo. dessa forma voce faz o DTO ou a projection, para devolver apenas esses dois campos.