Estou usando o JPA no meu projeto.
Cheguei a uma consulta na qual preciso fazer a operação de junção em cinco tabelas. Então eu criei uma consulta nativa que retorna cinco campos.
Agora eu quero converter o objeto de resultado em java POJO class que contém as mesmas cinco Strings.
Existe alguma maneira no JPA de converter diretamente esse resultado na lista de objetos POJO?
Eu vim para a seguinte solução ..
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativeSQL",
query = "SELECT * FROM Actors",
resultClass = db.Actor.class),
@NamedNativeQuery(
name = "nativeSQL2",
query = "SELECT COUNT(*) FROM Actors",
resultClass = XXXXX) // <--------------- problem
})
Agora, aqui em resultClass, precisamos fornecer uma classe que seja a entidade JPA real? OU Podemos convertê-lo em qualquer classe JAVA POJO que contenha os mesmos nomes de coluna?
Respostas:
O JPA fornece um
SqlResultSetMapping
que permite mapear os retornos da sua consulta nativa em uma Entidadeou uma classe personalizada.EDIT JPA 1.0 não permite mapeamento para classes não-entidade. Somente no JPA 2.1, um ConstructorResult foi adicionado para mapear os valores de retorno de uma classe java.
Além disso, para o problema do OP em obter a contagem, deve ser suficiente definir um mapeamento de conjunto de resultados com um único
ColumnResult
fonte
ConstructorResult
como um dos parâmetrosSqlResultSetMapping
que permite usar um pojo com todos os campos definidos no construtor. Vou atualizar a resposta.Eu encontrei algumas soluções para isso.
Usando entidades mapeadas (JPA 2.0)
Usando o JPA 2.0, não é possível mapear uma consulta nativa para um POJO, isso só pode ser feito com uma entidade.
Por exemplo:
Mas, neste caso,
Jedi
deve ser uma classe de entidade mapeada.Uma alternativa para evitar o aviso desmarcado aqui seria usar uma consulta nativa nomeada. Portanto, se declararmos a consulta nativa em uma entidade
Então, podemos simplesmente fazer:
Isso é mais seguro, mas ainda estamos restritos a usar uma entidade mapeada.
Mapeamento Manual
Uma solução que experimentei um pouco (antes da chegada do JPA 2.1) estava fazendo o mapeamento contra um construtor POJO usando um pouco de reflexão.
Esse método basicamente pega uma matriz de tupla (retornada por consultas nativas) e a mapeia em uma classe POJO fornecida, procurando por um construtor que tenha o mesmo número de campos e o mesmo tipo.
Em seguida, podemos usar métodos convenientes, como:
E podemos simplesmente usar esta técnica da seguinte maneira:
JPA 2.1 com @SqlResultSetMapping
Com a chegada do JPA 2.1, podemos usar a anotação @SqlResultSetMapping para resolver o problema.
Precisamos declarar um mapeamento de conjunto de resultados em algum lugar de uma entidade:
E então simplesmente fazemos:
Obviamente, nesse caso
Jedi
, não precisa ser uma entidade mapeada. Pode ser um POJO comum.Usando mapeamento XML
Eu sou um daqueles que consideram a adição de todas essas informações
@SqlResultSetMapping
bastante invasivas em minhas entidades, e particularmente não gosto da definição de consultas nomeadas dentro de entidades, então, alternativamente, faço tudo isso noMETA-INF/orm.xml
arquivo:E essas são todas as soluções que eu conheço. Os dois últimos são a maneira ideal se podemos usar o JPA 2.1.
fonte
@SqlResultSetMapping
deve ser colocado em uma entidade, porque é disso que o JPA vai ler os metadados. Você não pode esperar que a JPA inspecione seus POJOs. A entidade na qual você coloca o mapeamento é irrelevante, talvez a que esteja mais relacionada aos seus resultados no POJO. Como alternativa, o mapeamento pode ser expresso em XML para evitar o acoplamento com uma entidade totalmente não relacionada.@SqlResultSetMapping
, pode ser interessante notar que aJedi
classe exigirá um construtor all-arg e a@ColumnResult
anotação poderá precisar dotype
atributo adicionado às conversões que podem não estar implícitas (eu precisava adicionartype = ZonedDateTime.class
algumas colunas).Sim, com o JPA 2.1 é fácil. Você tem anotações muito úteis. Eles simplificam sua vida.
Primeiro, declare sua consulta nativa e, em seguida, o mapeamento do conjunto de resultados (que define o mapeamento dos dados retornados pelo banco de dados aos seus POJOs). Escreva para a sua turma POJO (não incluída aqui por questões de brevidade). Por último, mas não menos importante: crie um método em um DAO (por exemplo) para chamar a consulta. Isso funcionou para mim em um aplicativo dropwizard (1.0.0).
Primeiro declare uma consulta nativa em uma classe de entidade:
Abaixo, você pode adicionar a declaração de mapeamento do conjunto de resultados:
Posteriormente em um DAO, você pode consultar a consulta como
É isso aí.
fonte
Se você usar
Spring-jpa
, este é um complemento para as respostas e esta pergunta. Corrija isso se houver alguma falha. Eu usei principalmente três métodos para obter o "resultado de mapeamentoObject[]
para um pojo" com base nas necessidades práticas que eu atendo:sql
com o seuEntity
são suficientes.O antigo 2 falhou e eu tenho que usar um
nativeQuery
. Aqui estão os exemplos. O pojo esperava:Método 1 : Mude o pojo para uma interface:
E repositório:
Método 2 : Repositório:
Nota: a sequência de parâmetros do construtor POJO deve ser idêntica na definição de POJO e no sql.
Método 3 : Use
@SqlResultSetMapping
e@NamedNativeQuery
emEntity
como o exemplo de resposta de Edwin Dalorzo.Os dois primeiros métodos chamariam muitos manipuladores intermediários, como conversores personalizados. Por exemplo,
AntiStealing
define asecretKey
, antes de persistir, um conversor é inserido para criptografá-lo. Isso resultaria nos 2 primeiros métodos retornando um retorno convertidosecretKey
que não é o que eu quero. Enquanto o método 3 superaria o conversor, e retornadosecretKey
seria o mesmo que ele é armazenado (um criptografado).fonte
O procedimento de desempacotamento pode ser executado para atribuir resultados a não-entidade (que é Beans / POJO). O procedimento é o seguinte.
O uso é para implementação do JPA-Hibernate.
fonte
JobDTO
deve ter o construtor padrão. Ou você pode implementar seu próprio transformador com base naAliasToBeanResultTransformer
implementação.Primeiro declare as seguintes anotações:
Anote seu POJO da seguinte maneira:
Em seguida, escreva o processador de anotação:
Use a estrutura acima da seguinte maneira:
fonte
BeanUtils
?A maneira mais fácil é usar essas projeções . Ele pode mapear os resultados da consulta diretamente para interfaces e é mais fácil de implementar do que usar SqlResultSetMapping.
Um exemplo é mostrado abaixo:
Os campos da interface projetada devem corresponder aos campos nesta entidade. Caso contrário, o mapeamento do campo poderá ser interrompido.
Além disso, se você usar a
SELECT table.column
notação, defina sempre os aliases que correspondem aos nomes da entidade, conforme mostrado no exemplo.fonte
No hibernate, você pode usar esse código para mapear facilmente sua consulta nativa.
fonte
Usando o Hibernate:
fonte
Estilo antigo usando ResultSet
fonte
Como outros já mencionaram todas as soluções possíveis, estou compartilhando minha solução alternativa.
Na minha situação
Postgres 9.4
, enquanto trabalhava comJackson
,Tenho certeza que você pode encontrar o mesmo para outros bancos de dados.
Também FYI, JPA 2.0 resultados da consulta nativa como mapa
fonte
Não tenho certeza se isso se encaixa aqui, mas tive uma pergunta semelhante e encontrei a seguinte solução / exemplo simples para mim:
No meu caso, eu tive que usar partes SQL definidas em Strings em outro lugar, então não pude usar apenas NamedNativeQuery.
fonte
Estilo antigo usando o Resultset
fonte
Resolvemos o problema da seguinte maneira:
fonte
Veja o exemplo abaixo para usar um POJO como pseudoentidade para recuperar o resultado da consulta nativa sem usar SqlResultSetMapping complexo. Só precisa de duas anotações, uma @Enity nua e uma @ id dummy no seu POJO. @Id pode ser usado em qualquer campo de sua escolha, um campo @Id pode ter chaves duplicadas, mas não valores nulos.
Como o @Enity não mapeia para nenhuma tabela física, esse POJO é chamado de pseudo-entidade.
Ambiente: eclipselink 2.5.0-RC1, jpa-2.1.0, mysql-connector-java-5.1.14
Você pode baixar o projeto completo do maven aqui
A consulta nativa é baseada nos funcionários de amostra do mysql db http://dev.mysql.com/doc/employee/en/employees-installation.html
persistence.xml
Employee.java
EmployeeNativeQuery.java
fonte
list
é, supostamente, uma lista deEmployee
, por que o loop for-each está repetindo um tipoObject
? Se você escrever seu loop for-each,for(Employee emp : list)
descobrirá que sua resposta está errada e o conteúdo da sua lista não é empregado e que esse aviso suprimido teve o objetivo de alertá-lo sobre esse possível erro.List<Employee> list = (List<Employee>) query.getResultList();
Alterarfor (Object emp : list)
parafor (Employee emp : list)
melhor, mas nenhum erro será mantido,Object emp
pois a lista é uma instância deList<Employee>
. Eu mudei o código no projeto git, mas não aqui para manter seu comentário relevante para a postagem originalQuery query = em.createNativeQuery("select * ...", Employee.class);
persistence.xml, a consulta nativa retorna uma lista de Employee. Acabei de efetuar o check-out e executar o projeto sem problemas. Se você configurar os funcionários de amostra do mysql db localmente, poderá executar o projeto tambémEmployee
que eu suponho ser uma entidade. Não é?se você estiver usando o Spring, poderá usar
org.springframework.jdbc.core.RowMapper
Aqui está um exemplo:
fonte
Usando o Hibernate:
fonte
Maneira simples de converter consulta SQL em coleção de classe POJO,
fonte
Tudo que você precisa é de um DTO com um construtor:
e chame:
fonte
Use
DTO Design Pattern
. Foi usado emEJB 2.0
. A entidade foi gerenciada por contêiner.DTO Design Pattern
é usado para resolver esse problema. Mas, pode ser usado agora, quando o aplicativo for desenvolvidoServer Side
eClient Side
separadamente.DTO
é usado quandoServer side
não deseja passar / retornarEntity
com anotação paraClient Side
.Exemplo de DTO:
PersonEntity.java
PersonDTO.java
DTOBuilder.java
EntityBuilder.java <- pode ser necessário
fonte