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.