with query createnativequery create java hibernate jpa pojo

java - createnativequery - Mapeo de los resultados de NativeQuery en un POJO



query native java (6)

Estoy intentando asignar los resultados de una consulta nativa a un POJO usando @SqlResultSetMapping con @ConstructorResult. Aquí está mi código:

@SqlResultSetMapping(name="foo", classes = { @ConstructorResult( targetClass = Bar.class, columns = { @ColumnResult(name = "barId", type = Long.class), @ColumnResult(name = "barName", type = String.class), @ColumnResult(name = "barTotal", type = Long.class) }) }) public class Bar { private Long barId; private String barName; private Long barTotal; ...

Y luego en mi DAO:

Query query = em.createNativeQueryBar(QUERY, "foo"); ... set some parameters ... List<Bar> list = (List<Bar>) query.getResultList();

He leído que esta funcionalidad solo es compatible con JPA 2.1, pero eso es lo que estoy usando. Aquí está mi dependencia:

<dependency> <groupId>org.hibernate.javax.persistence</groupId> <artifactId>hibernate-jpa-2.1-api</artifactId> <version>1.0.0.Final</version> </dependency>

Encontré un par de recursos, incluido este: mapeo @ConstructorResult en jpa 2.1 . Pero sigo sin tener suerte.

¿Qué me estoy perdiendo? ¿Por qué no se puede encontrar el SqlResultSetMapping?

javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown SqlResultSetMapping [foo]


Ejemplo de trabajo corto:

  • Clase DTO POJO

    @lombok.Getter @lombok.AllArgsConstructor public class StatementDto { private String authorName; private Date createTime; }

  • Bean de repositorio:

    @Repository public class StatementNativeRepository { @PersistenceContext private EntityManager em; static final String STATEMENT_SQLMAP = "Statement-SQL-Mapping"; public List<StatementDto> findPipelinedStatements() { Query query = em.createNativeQuery( "select author_name, create_time from TABLE(SomePipelinedFun(''xxx''))", STATEMENT_SQLMAP); return query.getResultList(); } @SqlResultSetMapping(name= STATEMENT_SQLMAP, classes = { @ConstructorResult(targetClass = StatementDto.class, columns = { @ColumnResult(name="author_name",type = String.class), @ColumnResult(name="create_time",type = Date.class) } ) }) @Entity class SQLMappingCfgEntity{@Id int id;} // <- walkaround }


Pude hacerlo de esta manera:

Session session = em().unwrap(Session.class); SQLQuery q = session.createSQLQuery("YOUR SQL HERE"); q.setResultTransformer( Transformers.aliasToBean( MyNotMappedPojoClassHere.class) ); List<MyNotMappedPojoClassHere> postList = q.list();


QLRM podría ser una alternativa: http://simasch.github.io/qlrm/

No está relacionado con una implementación de JPA específica y también funciona con JDBC.


Tengo una respuesta ligeramente variada que se deriva de la respuesta de Wildloop.
Aquí está mi respuesta:

Clase de constantes: Constantes.java

public class Constants { public final String TESTQUERYRESULT_MAPPING_NAME = "TestQueryResultMapping"; }

Clase de asignación de resultados: TestQueryResult.java

import lombok.Getter; import lombok.Setter; import javax.persistence.Entity; import javax.persistence.EntityResult; import javax.persistence.FieldResult; import javax.persistence.Id; import javax.persistence.SqlResultSetMapping; @Getter @Setter @SqlResultSetMapping( //name = "TestQueryResultMapping" name = Constants.TESTQUERYRESULT_MAPPING_NAME ,entities = @EntityResult( entityClass = TestQueryResult.class ,fields = { @FieldResult(name = "rowId", column = "row_id") ,@FieldResult(name = "rowName", column = "row_name") ,@FieldResult(name = "value", column = "row_value") } ) ) @Entity public class TestQueryResult { @Id private Integer rowId; private String rowName; private String value; }

Entonces ... en algún lugar de mi código de implementación del repositorio:

public class TestQueryRepository { //... some code here to get the entity manager here public TestQueryResult getTopMost(Integer rowName) { //... some code here String queryString = "... some query string here" + rowName; TestQueryResult testQueryResult = null; //this.entityManager.createNativeQuery(queryString ,"TestQueryResultMapping").getResultList(); List<TestQueryResult> results = this.entityManager.createNativeQuery(queryString ,Constants.TESTQUERYRESULT_MAPPING_NAME).getResultList(); if (results != null && !results.isEmpty()) { testQueryResult = results.get(0); } return testQueryResult; } }


... entonces viola! Tengo algunos resultados: D!

Aclamaciones,
Artanis Zeratul


@SqlResultSetMapping anotación @SqlResultSetMapping no se debe colocar en un POJO . Ponlo en (cualquier) clase @Entity . "Unknown SqlResultSetMapping [foo]" le dice que el proveedor de JPA no ve ninguna asignación bajo el nombre ''foo''. Por favor vea otra respuesta mía para el ejemplo correcto.


@Entity @SqlResultSetMapping(name="ConnexionQueryBean", entities={ @EntityResult(entityClass=com.collecteJ.business.bean.ConnexionQueryBean.class, fields={ @FieldResult(name="utilisateurId", column="UTILISATEUR_ID"), @FieldResult(name="nom", column="NOM"), @FieldResult(name="prenom", column="PRENOM"), @FieldResult(name="nomConnexion", column="NOM_CONNEXION"), @FieldResult(name="codeAgence", column="CODE_AGENCE"), @FieldResult(name="codeBanque", column="CODE_BANQUE"), @FieldResult(name="codeDevise", column="CODE_DEVISE"), @FieldResult(name="codeCollecteur", column="CODE_COLLECTEUR")}) }) public class ConnexionQueryBean implements Serializable { @Id private long utilisateurId; private String codeCollecteur; private String nom; private String prenom; private String nomConnexion; private String codeAgence; private String codeBanque; private String codeDevise; public ConnexionQueryBean() { } public long getUtilisateurId() { return utilisateurId; } public void setUtilisateurId(long utilisateurId) { this.utilisateurId = utilisateurId; } public String getCodeCollecteur() { return codeCollecteur; } public void setCodeCollecteur(String codeCollecteur) { this.codeCollecteur = codeCollecteur; } public String getNom() { return nom; } public void setNom(String nom) { this.nom = nom; } public String getPrenom() { return prenom; } public void setPrenom(String prenom) { this.prenom = prenom; } public String getNomConnexion() { return nomConnexion; } public void setNomConnexion(String nomConnexion) { this.nomConnexion = nomConnexion; } public String getCodeAgence() { return codeAgence; } public void setCodeAgence(String codeAgence) { this.codeAgence = codeAgence; } public String getCodeBanque() { return codeBanque; } public void setCodeBanque(String codeBanque) { this.codeBanque = codeBanque; } public String getCodeDevise() { return codeDevise; } public void setCodeDevise(String codeDevise) { this.codeDevise = codeDevise; } @Override public String toString() { return "ConnexionQueryBean{" + "utilisateurId=" + utilisateurId + ", codeCollecteur=" + codeCollecteur + ", nom=" + nom + ", prenom=" + prenom + ", nomConnexion=" + nomConnexion + ", codeAgence=" + codeAgence + ", codeBanque=" + codeBanque + ", codeDevise=" + codeDevise + ''}''; }

Esto no es realmente una entidad, ya que no coincide con ninguna tabla de base de datos. Pero las @Entity y @Id son obligatorias para que JPA entienda el mapeo. Si realmente no desea tener @Entity / @Id en esa clase, puede eliminar la anotación @SqlResultSetMapping y colocarla en cualquier otra entidad en la medida en que JPA pueda escanearla.

También debe asegurarse de que su contenido de @ComponentScan el paquete correspondiente; si está utilizando una configuración Spring basada en Java, debe declarar explícitamente su entidad en persistence.xml/orm.xml en el directorio META-INF .

Esta es la llamada

String connexionQuery = "SELECT u.UTILISATEUR_ID, u.NOM, u.PRENOM, u.NOM_CONNEXION, a.CODE_AGENCE, a.CODE_BANQUE, a.CODE_DEVISE, c.CODE_COLLECTEUR FROM UTILISATEUR u, AGENCE a, COLLECTEUR c " + " WHERE (a.CODE_AGENCE = c.CODE_AGENCE AND u.UTILISATEUR_ID = c.UTILISATEUR_ID AND u.NOM_CONNEXION = ''"+nomConnextion+"'')"; ConnexionQueryBean ConnexionResults = (ConnexionQueryBean) defaultService.getEntityManager().createNativeQuery(connexionQuery,"ConnexionQueryBean").getSingleResult(); System.out.println(ConnexionResults.toString());

Estoy usando Spring, JPA 2.1, Hibernate 5 y Oracle, creo que esto podría no ser posible con la versión inferior de JPA, encuentre más http://www.thoughts-on-java.org/result-set-mapping-complex-mappings/