2017-07-25 1 views
2

Folks!Alternative JPA de Hibernate Projections.property

Essayer de limiter quantité de colonnes extraites de DB et trouvé ceci: Hibernate Criteria Query to get specific columns

Criteria cr = session.createCriteria(User.class) 
    .setProjection(Projections.projectionList() 
     .add(Projections.property("id"), "id") 
     .add(Projections.property("Name"), "Name")) 
    .setResultTransformer(Transformers.aliasToBean(User.class)); 

    List<User> list = cr.list(); 

Cela fonctionne génial lorsque vous utilisez Hibernate, mais je suis en train de faire la même chose avec JPA (fournisseur JPA est Hibernate tho). Est-il possible de le faire avec JPA? Je veux dire limiter les colonnes avec CriteriaBuilder et mapper à un objet spécifique?

Aussi, j'ai vu ceci: https://docs.jboss.org/hibernate/orm/5.0/userguide/html_single/chapters/query/criteria/Criteria.html

Hibernate offers an older, legacy org.hibernate.Criteria API which should be considered deprecated. No feature development will target those APIs. Eventually, Hibernate-specific criteria features will be ported as extensions to the JPA javax.persistence.criteria.CriteriaQuery. For details on the org.hibernate.Criteria API, see Legacy Hibernate Criteria Queries. 

semble donc comme il est possible de le faire via les extensions de mise en veille prolongée pour JPA?

Répondre

0

Il n'y a pas de syntaxe alternative dans JPA, Hibernate est un sur-ensemble de JPA, il fournit des fonctionnalités au-delà des spécifications JPA. Dans JPA, vous devrez faire des projections individuellement de manière explicite avec une instruction select (dans votre cas, l'instruction multiselect).

Critères Query

// Create instance of CriteriaBuilder, where em is EntityManager 
CriteriaBuilder cb = em.getCriteriaBuilder();  

    // Use CriteriaBuilder interface to create an instance 
    // of CriteriaQuery. For multiselect result set is Object []. 
CriteriaQuery<Object[]> c = cb.createQuery(Object[].class); 

    // Establish the root of the query by invoking from() to get back a Root object. 
Root<User> user = c.from(User.class); 

    // Establish the SELECT clause of the query by passing the root into the multiselect() method 
criteriaQuery.multiselect(user.get("property1"), user.get("property2")); 

alternative serait appel constructeur:

CriteriaQuery<User> c = cb.createQuery(User.class); 
Root<User> user = c.from(User.class); 
c.select(cb.construct(User.class, 
         user.get("property1"), 
         user.get("property2"))); 

TupleQuery

CriteriaQuery<Tuple> c = cb.createTupleQuery(); 
    Root<User> user = c.from(User.class); 
    c.select(cb.tuple(user.get("property1"), user.get("property2"))); 
    Query query = entityManager.createQuery(c); 
    List<Tuple> results = query.getResultList(); 

Il est procédé également array() (retourne Object []) ainsi .

c.select(cb.array(user.get("property1"), user.get("property2"))); 
+0

Merci de nous en aviser! J'ai juste essayé votre solution..but: dans le premier cas le résultat de l'exécution (* getResultList *) est juste un tableau d'objets - ainsi le résultat n'est pas mappé à la classe User. Et la deuxième approche me donne * QuerySyntaxException: Impossible de trouver le constructeur approprié sur la classe * – cingulata

+0

Pour la deuxième approche, vous devez avoir un constructeur approprié. Multiselect renverra Object [] ou Tuple. Je vais inclure tuple dans l'exemple aussi. – fg78nc

+0

Merci, mais toujours la même chose - la liste qui est retournée n'est pas de type User. Avec Tuple, j'ai remarqué un comportement intéressant. Chaque Tuple a une propriété de membre, - dans notre cas c'est "id" et "name". Mais il n'est pas converti en type d'utilisateur automatiquement. Devrait-il être de cette manière? Je vois toujours que le SQL généré est correct, mais le résultat n'est pas mappé sur l'entité Utilisateur. On dirait que j'ai vraiment mal compris quelque chose. – cingulata