83 votes

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

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

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 : The method select(Selection<? extends T>) in the type CriteriaQuery<T> is not applicable for the arguments (Path<Object>) . Comment puis-je changer cela ? Je veux obtenir un type T qui n'a que des ID y VERSION et tous les autres sont des null .

Type T s'étend AbstractEntity qui contient ces deux champs.

entityClazz es T.class .

106voto

perissf Points 6899

L'une des méthodes JPA permettant d'obtenir uniquement des colonnes particulières consiste à demander un fichier Tuple objet.

Dans votre cas, vous devriez é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 disposez d'une classe représentant le résultat, comme par exemple T dans votre cas. T n'a pas besoin d'être une classe Entity. Si le T a un constructeur comme :

public T(Long id, Long version)

vous pouvez alors utiliser T directement dans votre CriteriaQuery constructeur :

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 plus d'informations.

13voto

EduardoRamirez Points 131
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

3voto

baba Points 3611

Tout d'abord, je ne vois pas vraiment pourquoi vous voudriez qu'un objet n'ait que l'ID et la Version, et que tous les autres props 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 simplement obtenir l'objet Session Hibernate à partir du délégué Em. Accès à une session Hibernate à partir d'un EJB en 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 renverra une liste d'objets dont l'ID et la version sont définis et tous les autres éléments à null, car le transformateur aliasToBean ne sera pas en mesure de les trouver. Encore une fois, je ne suis pas sûr de pouvoir penser à une situation où je voudrais faire cela.

-3voto

Abrar Ansari Points 62

Vous pouvez faire quelque chose comme ceci

Session session = app.factory.openSession();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery query = builder.createQuery();
Root<Users> root = query.from(Users.class);
query.select(root.get("firstname"));
String name = session.createQuery(query).getSingleResult();

où vous pouvez remplacer "firstname" par le nom de la colonne que vous souhaitez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X