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/