La cartographie des résultats de NativeQuery dans un POJO

j'essaie de mapper les résultats D'une requête Native à un POJO en utilisant @SqlResultSetMapping avec @ConstructorResult. Voici mon code:

@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;

...

et puis dans mon DAO:

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

j'ai lu que cette fonctionnalité est prise en charge uniquement dans JPA 2.1, mais c'est ce que j'utilise. Voici ma dépendance:

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

j'ai trouvé quelques ressources, dont celle-ci: @ConstructorResult la cartographie en jpa 2.1 . Mais je ne suis pas encore avoir de la chance.

Qu'est-ce que je rate? Pourquoi ne trouve-t-on pas le SqlResultSetMapping?

javax.persistence.PersistenceException: org.hibernate.MappingException: Unknown SqlResultSetMapping [foo]
23
demandé sur P̲̳x͓L̳ 2014-08-07 21:48:43

5 réponses

@SqlResultSetMapping annotation ne doit pas être mis sur un POJO . Mettez-le dans la classe @Entity . "Sqlresultsetmapping [foo] inconnu" vous dit, que le fournisseur JPA ne voit pas de cartographie sous le nom de 'foo'. S'il vous plaît voir une autre réponse de la mienne pour le bon exemple

25
répondu zbig 2017-05-23 12:26:32

Court exemple:

  • classe DTO POJO

    @lombok.Getter
    @lombok.AllArgsConstructor
    public class StatementDto {
        private String authorName;
        private Date createTime;
    }
    
  • référentiel bean:

    @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
    
    }
    
6
répondu wildloop 2016-03-20 01:26:59

je peux le faire de cette façon:

Session session = em().unwrap(Session.class);
SQLQuery q = session.createSQLQuery("YOUR SQL HERE");
q.setResultTransformer( Transformers.aliasToBean( MyNotMappedPojoClassHere.class) );
List<MyNotMappedPojoClassHere> postList = q.list();
4
répondu Emerson Moretto 2015-01-09 17:35:37
@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 + '}';
}

ce n'est pas vraiment une entité car elle ne correspond à aucune table de base de données. Mais les annotations @Entity et @Id sont obligatoires pour JPA pour comprendre la cartographie. Si vous ne voulez pas vraiment avoir @Entity / @Id dans cette classe, vous pouvez supprimer l'annotation @SqlResultSetMapping et la mettre dans n'importe quelle autre entité aussi loin que JPA peut la Scanner.

, Vous devez également vous assurer que votre @ComponentScan contenu du paquet correspondant, si vous êtes en utilisant une configuration Java, vous devez explicitement déclarer votre entité dans le répertoire persistence.xml/orm.xml sous le répertoire META-INF .

C'est l'appel

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());

j'utilise Spring, JPA 2.1, Hibernate 5 et Oracle, je pense que cela pourrait ne pas être possible avec la version inférieure de JPA, en savoir plus http://www.thoughts-on-java.org/result-set-mapping-complex-mappings /

1
répondu benito 2016-11-25 12:37:47

QLRM pourrait être une alternative: http://simasch.github.io/qlrm/

il n'est pas lié à une mise en œuvre spécifique de L'app et fonctionne également avec JDBC.

0
répondu Simon Martinelli 2016-11-25 12:41:43