web-dev-qa-db-fra.com

API JPA & Criteria - Sélectionnez uniquement des colonnes spécifiques

Je voudrais sélectionner uniquement des colonnes spécifiques (ex. SELECT a FROM b). J'ai un DAO générique et ce que j'ai proposé est:

public List<T> getAll(boolean idAndVersionOnly) {
    CriteriaBuilder builder = manager.getCriteriaBuilder();
    CriteriaQuery<T> criteria = builder.createQuery(entityClazz);
    Root<T> root = criteria.from(entityClazz);
    if (idAndVersionOnly) {
        criteria.select(root.get("ID").get("VERSION")); // HERE IS ERROR
    } else {
        criteria.select(root);
    }
    return manager.createQuery(criteria).getResultList();
}

Et l'erreur est la suivante: The method select(Selection<? extends T>) in the type CriteriaQuery<T> is not applicable for the arguments (Path<Object>). Comment devrais-je changer cela? Je souhaite obtenir un objet de type T comportant uniquement les champs ID et VERSION. Tous les autres sont null.

Tapez T étend AbstractEntity qui contient ces 2 champs.

entityClazz est T.class.

58
BartoszCichecki

L'un des moyens JPA d'obtenir uniquement des colonnes particulières est de demander un objet Tuple .

Dans votre cas, vous devez écrire quelque chose comme ceci:

CriteriaQuery<Tuple> cq = builder.createTupleQuery();
// write the Root, Path elements as usual
Root<EntityClazz> root = cq.from(EntityClazz.class);
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION));  //using metamodel
List<Tuple> tupleResult = em.createQuery(cq).getResultList();
for (Tuple t : tupleResult) {
    Long id = (Long) t.get(0);
    Long version = (Long) t.get(1);
}

Une autre approche est possible si vous avez une classe représentant le résultat, comme T dans votre cas. T n'a pas besoin d'être une classe d'entité. Si T a un constructeur comme:

public T(Long id, Long version)

alors vous pouvez utiliser T directement dans votre constructeur CriteriaQuery:

CriteriaQuery<T> cq = builder.createQuery(T.class);
// write the Root, Path elements as usual
Root<EntityClazz> root = cq.from(EntityClazz.class);
cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION));  //using metamodel
List<T> result = em.createQuery(cq).getResultList();

Voir ceci lien pour référence ultérieure.

84
perissf
cq.select(cb.construct(entityClazz.class, root.get("ID"), root.get("VERSION")));  // HERE IS NO ERROR

https://wiki.Eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Criteria#Constructors

8
EduardoRamirez

Tout d'abord, je ne vois pas vraiment pourquoi vous voudriez qu'un objet ayant uniquement ID et Version, et tous les autres accessoires, soient nuls. Cependant, voici un code qui le fera pour vous (qui n’utilise pas JPA Em, mais Hibernate normal. Je suppose que vous pouvez trouver l’équivalence dans JPA ou tout simplement obtenir l’obj Hibernate Session du em delegate Accès Session Hibernate d'EJB utilisant EntityManager ):

List<T> results = session.createCriteria(entityClazz)
    .setProjection( Projections.projectionList()
        .add( Property.forName("ID") )
        .add( Property.forName("VERSION") )
    )
    .setResultTransformer(Transformers.aliasToBean(entityClazz); 
    .list();

Cela retournera une liste d'objets ayant leur ID, leur version et tous les autres accessoires à null, car le transformateur aliasToBean ne pourra pas les trouver. Encore une fois, je ne suis pas sûr de pouvoir penser à une situation dans laquelle je voudrais faire cela.

3
Nikola Yovchev