Criteria fluent avec Querydsl

Parmi les nouveautés de JPA2 figure l’API Criteria, inspirée de celle présente depuis longtemps dans Hibernate.

Son intérêt réside dans le fait qu’elle permet d’écrire des requêtes type-safe et que les éléments sont générés à partir du code source (via l’APT). Finis les problèmes de refactoring!
Malheureusement, le design de cette API est franchement un échec, notamment parce qu’elle n’est absolument pas fluent.

Là où en JPQL vous écririez simplement :

1
2
3
4
String jpql = "select p from Person p where p.eyeColor = :eyeColor";
TypedQuery<Person> query = em.createQuery(jpql, Person.class);
query.setParameter("eyeColor", "brown");
List<Person> people = query.getResultList();

Avec JPA Criteria, il vous faut écrire :

1
2
3
4
5
6
7
8
9
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> personRoot = criteria.from(Person.class);
criteria.select(personRoot);
ParameterExpression<String> eyeColorParam = builder.parameter(String.class);
criteria.where(builder.equal(personRoot.get(Person_.eyeColor), eyeColorParam));
TypedQuery<Person> query = em.createQuery(criteria);
query.setParameter(eyeColorParam, "brown");
List<Person> people = query.getResultList();

Si quelqu’un trouve ça lisible, qu’il m’explique…

C’est là qu’intervient une alternative de choix : Querydsl. Le principe est exactement le même : s’appuyer sur des éléments générés à partir des entités avec l’APT (Java 6, donc), mais le résultat est beaucoup plus élégant.

Avec Querydsl, l’exemple précédent donne :

1
2
3
JPAQuery query = new JPAQuery(em);
QPerson person = QPerson.person;
List<Person> people = query.from(person).where(person.eyeColor.eq("brown")).list(person);

Mieux, non? :)

A noter que querydsl s’interface aussi avec JDO, JDBC, Lucene, etc…

VN:R_U [1.9.22_1171]
Rating: 0 (from 0 votes)
Share
Ce contenu a été publié dans JPA, avec comme mot(s)-clef(s) , . Vous pouvez le mettre en favoris avec ce permalien.

3 réponses à Criteria fluent avec Querydsl

  1. Joan Zapata dit :

    Ce n’est pas du tout le souvenir que m’avait laissé Criteria. Si je ne me trompe pas on peut d’ailleurs faire la même requête avec Criteria avec ce code là :

    1
    DetachedCriteria criteria = DetachedCriteria.forClass(Person.class).add(Restrictions.eq("eyeColor", "brown"));

    Je conviens que la requête avec Querydsl est plus lisible, et surtout plus typée, et ça c’est cool !

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  2. Tu confonds l’API Criteria propriétaire d’Hibernate (non typée) et celle de JPA2 (typée).

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)
  3. Il convient de préciser un peu les choses, la remarque de Joan sur son souvenir de l’API Criteria n’est pas totalement infondée.

    L’API Criteria Hibernate s’utilise, de base, sans annotation processing / generation de code.

    Elle a pour intérêt de permettre la construction de requêtes donc la structure est dynamique et dépend d’un contexte. Là où JPQL / HQL nécessite d’utiliser des StringBuilders, ce qui est pas top du tout…

    Un “vrai” ( :P ) example de l’API Criteria Hibernate :

    1
    2
    3
    Criteria criteria = session.createCriteria(MonBean.class);
    if(uneCondition)
      criteria.add(Expression.ge("nomDuParametre", valeurDuParametre));

    Cette API n’est pas totalement illisible en soit. Mais elle garde un problème : elle n’est toujours pas typesafe, puis “nomDuParametre” est une String.

    C’est là que les gars d’Hibernate se sont dit “c’est plus possible”, et ont créé Hibernate Metamodel Generator. Plusieurs propositions d’API ont été faite, mais c’est finalement la proposition de Gavin King qui l’a emportée (après tout, c’est le chef) : une API imbitable, mais qui couvre toute la spec JPA.

    JPA2 embarque tout ça sous le nom Criteria API, ce qui peut donner lieu à quelque confusions…

    Par ailleurs, notez bien que QueryDSL ne couvre visiblement pas toute la spec JPA.. mais après tout, rien n’empêche de l’utiliser 80% du temps et de revenir à des choses plus classiques pour les cas un peu touchy.

    VN:R_U [1.9.22_1171]
    Rating: 0 (from 0 votes)

Laisser un commentaire