JPA et Hibernate - Critères vs JPQL ou HQL

295

Quels sont les avantages et les inconvénients de l'utilisation des critères ou HQL ? L'API Criteria est une belle façon orientée objet d'exprimer des requêtes dans Hibernate, mais parfois les requêtes Criteria sont plus difficiles à comprendre / construire que HQL.

Quand utilisez-vous les critères et quand HQL? Que préférez-vous dans quels cas d'utilisation? Ou est-ce juste une question de goût?

cretzel
la source
La bonne réponse serait «dépend du cas d'utilisation».
Hace
Et qu'en est-il de cet outil ? Il permet de construire des requêtes communes de manière objet: Clause protégée select () {return em.select ("DISTINCT i") .from (this.getName (), "i") .joinFetch ("i.locale lf") } public T findBySlug (String slug) {return (T) this.select () .join ("i.locale l"); .where ("l.slug =?", slug) .fetchSingle (); }
Vojtěch
1
Définition d'une question d'opinion, mais les gens n'ont pas saisi l'occasion pour la fermer ... selon le site FAQ

Réponses:

212

Je préfère principalement les requêtes de critères pour les requêtes dynamiques. Par exemple, il est beaucoup plus facile d'ajouter de l'ordre de façon dynamique ou de laisser certaines parties (par exemple des restrictions) en fonction de certains paramètres.

D'un autre côté, j'utilise HQL pour des requêtes statiques et complexes, car il est beaucoup plus facile de comprendre / lire HQL. De plus, HQL est un peu plus puissant, je pense, par exemple pour différents types de jointures.

cretzel
la source
13
De plus, bien que les critères semblent un peu plus sûrs pour le type, la seule chose qui peut vous faire vous sentir en sécurité est le test.
Existe-t-il de bons exemples qui montrent pourquoi HQL est meilleur que les critères API dans certains cas? J'ai lu la fin d'un blog, mais je n'ai rien compris. Je vous serais reconnaissant de bien vouloir nous aider. Merci. Lien - javalobby.org/articles/hibernatequery102
Erran Morad
Toutes les raisons ci-dessus - je préfère également les critères au HQL car c'est plus sûr pour le programmeur, ce qui diminue les erreurs de codage - la compilation sur la chaîne HQL n'est pas validée.
nuno
Cependant, il y a le problème de récupérer des entités distinctes tout en paginant. En faisant cela, je choisirais HQL pour éviter les problèmes ...
Anthony Webster
l'utilisation d'une requête de critères avec un métamodèle pour les noms de colonne aide lors du refactoring à ne rien casser et avec une simple commande à partir d'un IDE moderne pour renommer toutes les occurrences du code.
Massimo
92

Il existe une différence en termes de performances entre HQL et critèresQuery, chaque fois que vous lancez une requête à l'aide de critèresQuery, il crée un nouvel alias pour le nom de table qui ne se reflète pas dans le dernier cache interrogé pour n'importe quelle base de données. Cela entraîne une surcharge de compilation du SQL généré, ce qui prend plus de temps à exécuter.

Concernant les stratégies de récupération [http://www.hibernate.org/315.html]

  • Les critères respectent les paramètres de paresse dans vos mappages et garantissent que ce que vous voulez charger est chargé. Cela signifie qu'une requête Critères peut entraîner plusieurs instructions SQL SELECT immédiates pour extraire le sous-graphique avec toutes les associations et collections mappées non paresseuses. Si vous souhaitez modifier le "comment" et même le "quoi", utilisez setFetchMode () pour activer ou désactiver l'extraction de jointure externe pour une collection ou une association particulière. Les requêtes de critères respectent également complètement la stratégie de récupération (joindre vs sélectionner vs sous-sélectionner).
  • HQL respecte les paramètres de paresse dans vos mappages et garantit que ce que vous voulez charger est chargé. Cela signifie qu'une requête HQL peut entraîner plusieurs instructions SELECT SQL immédiates pour extraire le sous-graphique avec toutes les associations et collections mappées non paresseuses. Si vous souhaitez modifier le "comment" et même le "quoi", utilisez LEFT JOIN FETCH pour activer l'extraction de jointure externe pour une collection particulière ou l'association plusieurs à un ou un à un annulable, ou JOIN FETCH pour activer jointure interne récupérant une association plusieurs-à-un ou un-à-un non nulle. Les requêtes HQL ne respectent aucune fetch = "join" définie dans le document de mappage.
Varun Mehta
la source
1
Je fais juste remarquer à quiconque navigue. que cette réponse date de 2008. ce n'est peut-être plus le cas. dimovelev.blogspot.com/2015/02/…
Amalgovinus
41

Les critères sont une API orientée objet, tandis que HQL signifie la concaténation de chaînes. Cela signifie que tous les avantages de l'orientation objet s'appliquent:

  1. Toutes choses étant égales par ailleurs, la version OO est un peu moins sujette aux erreurs. Toute ancienne chaîne peut être ajoutée à la requête HQL, alors que seuls les objets Criteria valides peuvent en faire une arborescence Criteria. En effet, les classes de critères sont plus contraintes.
  2. Avec l'auto-complétion, l'OO est plus découvrable (et donc plus facile à utiliser, du moins pour moi). Vous n'avez pas nécessairement besoin de vous rappeler quelles parties de la requête vont où; l'IDE peut vous aider
  3. Vous n'avez pas non plus besoin de vous souvenir des détails de la syntaxe (comme quels symboles vont où). Tout ce que vous devez savoir, c'est comment appeler des méthodes et créer des objets.

Étant donné que HQL ressemble beaucoup à SQL (que la plupart des développeurs connaissent déjà très bien), ces arguments "ne pas avoir à se rappeler" n'ont pas autant de poids. Si HQL était plus différent, alors ce serait plus important.

Craig Walker
la source
12
Ces arguments ne tiennent pas la route (par rapport à HQL). Il ne doit pas impliquer de concaténation de chaînes. Le fait que la version OO soit moins sujette aux erreurs n'est pas corroboré. Il est également sujet aux erreurs, mais d'un type différent. L'effort de savoir quelles méthodes appeler n'est pas très différent de savoir quels symboles appeler dans HQL (je veux dire, sérieusement, nous ne résolvons pas les EDP ici.)
luis.espinal
Existe-t-il de bons exemples qui montrent pourquoi HQL est meilleur que les critères API dans certains cas? J'ai lu la fin d'un blog, mais je n'ai rien compris. Je vous serais reconnaissant de bien vouloir nous aider. Merci. Lien - javalobby.org/articles/hibernatequery102
Erran Morad
1
Les requêtes nommées HQL sont compilées au moment du déploiement et à ce stade, les champs manquants (peut-être pour les mauvais refacteurs?) Sont détectés. Je pense que cela rend le code plus résistant et en fait moins sujet aux erreurs que les critères.
narduk
La saisie semi-automatique dans les critères est pratiquement inutile car les propriétés ne sont que des chaînes.
Lluis Martinez
35

J'utilise généralement des critères lorsque je ne sais pas quelles entrées seront utilisées sur quels éléments de données. Comme sur un formulaire de recherche où l'utilisateur peut saisir de 1 à 50 éléments et je ne sais pas ce qu'il recherchera. Il est très facile d'ajouter simplement plus de critères au fur et à mesure que je vérifie ce que recherche l'utilisateur. Je pense qu'il serait un peu plus gênant de mettre une requête HQL dans cette circonstance. HQL est génial quand je sais exactement ce que je veux.

Arthur Thomas
la source
1
Ceci est un bon commentaire. Nous construisons actuellement de très grandes chaînes HQL pour un formulaire de recherche qui contient de nombreux objets différents via des jointures. Ça a l'air moche. Va voir si un critère peut nettoyer ça. Intéressant ...
cbmeeks
Merci. Ceci est un excellent exemple. Pouvez-vous m'en donner un peu plus?
Erran Morad
31

HQL est beaucoup plus facile à lire, plus facile à déboguer à l'aide d'outils comme le plugin Eclipse Hibernate et plus facile à enregistrer. Les requêtes de critères sont meilleures pour créer des requêtes dynamiques où une grande partie du comportement est déterminée lors de l'exécution. Si vous ne connaissez pas SQL, je pourrais comprendre à l'aide de requêtes de critères, mais dans l'ensemble, je préfère HQL si je sais ce que je veux à l'avance.

Brian Deterling
la source
22

Les critères sont le seul moyen de spécifier des recherches de clés naturelles qui tirent parti de l'optimisation spéciale dans le cache de requêtes de deuxième niveau. HQL n'a aucun moyen de spécifier le conseil nécessaire.

Vous pouvez trouver plus d'informations ici:

Alex Miller
la source
21

Criteria Api est l'un des bons concepts d'Hibernate. selon moi, ce sont les quelques points par lesquels nous pouvons faire la différence entre HQL et Criteria Api

  1. HQL consiste à effectuer des opérations de sélection et de non-sélection sur les données, mais les critères ne concernent que la sélection des données, nous ne pouvons pas effectuer d'opérations de non-sélection à l'aide de critères.
  2. HQL convient à l'exécution de requêtes statiques, tandis que, comme Criteria, convient à l'exécution de requêtes dynamiques
  3. HQL ne prend pas en charge le concept de pagination , mais nous pouvons atteindre la pagination avec les critères.
  4. Les critères prenaient plus de temps à exécuter que HQL.
  5. Avec Criteria, nous sommes en sécurité avec SQL Injection en raison de sa génération de requêtes dynamiques, mais dans HQL, car vos requêtes sont soit fixes soit paramétrées, il n'y a pas de sécurité contre SQL Injection
Arvind
la source
11
Quelques points de pagination sont là dans HQL: vous pouvez utiliser limit offset:rows En hql vous pouvez éviter l'injection sql en utilisantsetParameter
Viswanath Lekshmanan
13

Pour utiliser le meilleur des deux mondes, l'expressivité et la concision de HQL et la nature dynamique de Criteria envisagent d'utiliser Querydsl .

Querydsl prend en charge JPA / Hibernate, JDO, SQL et Collections.

Je suis le responsable de Querydsl, donc cette réponse est biaisée.

Timo Westkämper
la source
13

Pour moi, les critères sont assez faciles à comprendre et à effectuer des requêtes dynamiques. Mais le défaut que je dis jusqu'à présent est qu'il charge toutes les relations multiples, etc. car nous n'avons que trois types de FetchModes, c'est-à-dire Select, Proxy et Default et dans tous ces cas, il charge plusieurs (je peux me tromper si l'aide moi :))

Le deuxième problème avec les critères est qu'il charge un objet complet, c'est-à-dire que si je veux simplement charger EmpName d'un employé, il ne fournira pas cet objet, il proposera un objet employé complet et je peux obtenir EmpName à cause de cela, cela fonctionne vraiment mal dans rapports . où en tant que HQL, il suffit de charger (ne charge pas l'association / les relations) ce que vous voulez, donc augmentez les performances plusieurs fois.

Une caractéristique de Criteria est qu'il protégera u de SQL Injection en raison de sa génération de requêtes dynamiques où, comme dans HQL, vos requêtes sont soit fixes, soit paramétrées et ne sont donc pas à l'abri de SQL Injection.

De plus, si vous écrivez HQL dans vos fichiers aspx.cs, vous êtes étroitement couplé avec ur DAL.

Dans l'ensemble, ma conclusion est qu'il y a des endroits où vous ne pouvez pas vivre sans rapports HQL, alors utilisez-les autrement. Les critères sont plus faciles à gérer.

Zafar
la source
13
HQL n'est PAS protégé contre les injections SQL
Varun Mehta
Je pense que Criteria n'est pas sûr pour les injections. Voir mon article ici: stackoverflow.com/questions/6746486/…
Mister Smith
4
HQL IS sql injection safe en ajoutant 'setParameter'
Javatar
2
@Zafar: vous ne pouvez sélectionner que certaines propriétés d'une entité à l'aide de projections
Răzvan Flavius ​​Panda
@Zafar, vous pouvez définir la projection dans la requête de critères pour sélectionner des colonnes particulières. Vous pouvez récupérer EmpName, pas besoin de récupérer l'objet complet.
Khatri
12

API de critères

L'API de critères est mieux adaptée aux requêtes générées dynamiquement. Ainsi, si vous souhaitez ajouter des filtres de clause WHERE, des clauses JOIN ou modifier la clause ORDER BY ou les colonnes de projection, l'API Criteria peut vous aider à générer la requête de manière dynamique d'une manière qui empêche également les attaques par injection SQL .

D'un autre côté, les requêtes Criteria sont moins expressives et peuvent même conduire à des requêtes SQL très compliquées et inefficaces, comme expliqué dans cet article .

JPQL et HQL

JPQL est le langage de requête d'entité standard JPA tandis que HQL étend JPQL et ajoute des fonctionnalités spécifiques à Hibernate.

JPQL et HQL sont très expressifs et ressemblent à SQL. Contrairement à l'API Criteria, JPQL et HQL facilitent la prédiction de la requête SQL sous-jacente générée par le fournisseur JPA. Il est également beaucoup plus facile de revoir ses requêtes HQL que celles de critères.

Il convient de noter que la sélection d'entités avec JPQL ou l'API Criteria est logique si vous devez les modifier. Sinon, une projection DTO est un bien meilleur choix.

Conclusion

Si vous n'avez pas besoin de varier la structure de requête d'entité, utilisez JPQL ou HQL. Si vous devez modifier les critères de filtrage ou de tri ou modifier la projection, utilisez l'API Criteria.

Cependant, ce n'est pas parce que vous utilisez JPA ou Hibernate que vous ne devez pas utiliser SQL natif. Les requêtes SQL sont très utiles et JPQL et l'API Criteria ne remplacent pas SQL. Consultez cet article pour plus de détails sur ce sujet.

Vlad Mihalcea
la source
11

Pour moi, la plus grande victoire sur les critères est l'exemple d'API, où vous pouvez passer un objet et hibernate construira une requête basée sur ces propriétés d'objet.

En plus de cela, l'API critères a ses caprices (je pense que l'équipe hibernate retravaille l'api), comme:

  • un critère.createAlias ​​("obj") force une jointure interne au lieu d'une jointure externe possible
  • vous ne pouvez pas créer le même alias deux fois
  • certaines clauses sql n'ont pas de contrepartie de critères simples (comme une sous-sélection)
  • etc.

J'ai tendance à utiliser HQL lorsque je veux des requêtes similaires à sql (supprimer des utilisateurs où status = 'bloqué'), et j'ai tendance à utiliser des critères lorsque je ne veux pas utiliser l'ajout de chaîne.

Un autre avantage de HQL est que vous pouvez définir toutes vos requêtes à l'avance, et même les externaliser dans un fichier.

Miguel Ping
la source
9

L'API des critères fournit une fonctionnalité distincte que ni SQL ni HQL ne fournit. c'est à dire. il permet de compiler le temps de vérification d'une requête.

user1165443
la source
7

Nous avons utilisé principalement des critères dans notre application au début, mais après son remplacement par HQL en raison de problèmes de performances.
Nous utilisons principalement des requêtes très complexes avec plusieurs jointures, ce qui conduit à plusieurs requêtes dans Criteria mais est très optimisé dans HQL.
Le cas est que nous utilisons seulement plusieurs propriétés sur un objet spécifique et non des objets complets. Avec Criteria, le problème était également la concaténation de chaînes.
Supposons que si vous devez afficher le nom et le prénom de l'utilisateur dans HQL, c'est assez facile, (name || ' ' || surname)mais dans Crteria, ce n'est pas possible.
Pour surmonter cela, nous avons utilisé ResultTransormers, où il y avait des méthodes où une telle concaténation était implémentée pour le résultat souhaité.
Aujourd'hui, nous utilisons principalement HQL comme ceci:

String hql = "select " +
            "c.uuid as uuid," +
            "c.name as name," +
            "c.objective as objective," +
            "c.startDate as startDate," +
            "c.endDate as endDate," +
            "c.description as description," +
            "s.status as status," +
            "t.type as type " +
            "from " + Campaign.class.getName() + " c " +
            "left join c.type t " +
            "left join c.status s";

Query query =  hibernateTemplate.getSessionFactory().getCurrentSession().getSession(EntityMode.MAP).createQuery(hql);
query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
return query.list();

dans notre cas, les enregistrements renvoyés sont des cartes des propriétés nécessaires.

Bojan Kraut
la source
1
Avec Criteria, vous pouvez utiliser org.hibernate.criterion.CriteriaSpecification.ALIAS_TO_ENTITY_MAP
AA.
Le retour d'une liste de cartes d'après mon expérience a de très mauvaises performances. Je préfère renvoyer une liste de tableaux d'objets ou une liste de beans (vous pouvez toujours définir un bean qui convient à votre jeu de résultats spécifique).
Lluis Martinez
7
  • HQL consiste à effectuer des opérations de sélection et de non-sélection sur les données, mais les critères ne concernent que la sélection des données, nous ne pouvons pas effectuer d'opérations de non-sélection à l'aide de critères
  • HQL convient à l'exécution de requêtes statiques, tandis que, comme Criteria, convient à l'exécution de requêtes dynamiques
  • HQL ne prend pas en charge le concept de pagination, mais nous pouvons atteindre la pagination avec les critères
  • Les critères prenaient plus de temps pour exécuter que HQL
  • Avec Criteria, nous sommes en sécurité avec SQL Injection en raison de sa génération de requêtes dynamiques, mais dans HQL, car vos requêtes sont fixes ou paramétrées, il n'y a pas de sécurité contre SQL Injection.

la source

Premraj
la source
Pour clarifier, les requêtes de critères utilisant l'API de critères d'Hibernate peuvent être disponibles pour les requêtes, mais les requêtes de critères JPA couvrent les sélections, les mises à jour et les suppressions. Voir CriteriaUpdate<T>et CriteriaDelete<T>pour référence.
Naros
5

Critère requête pour dynamiquement nous pouvons construire une requête basée sur nos entrées .. Dans le cas de la requête Hql est la requête statique une fois que nous construisons, nous ne pouvons pas changer la structure de la requête.

user1679378
la source
2
Mais non. Avec HQL, vous pouvez définir des propriétés avec l'identificateur «:», puis remplacer ces propriétés par des valeurs uniques. Par exemple, Query q = session.createQuery ("SELECT: aValue FROM my_table"); puis q.setParameter ("aValue", "some_column_name");
MattC
@MattC Dans votre exemple, vous modifiez les valeurs des paramètres, pas la structure de la requête.
Czar
4

Je ne veux pas frapper un cheval mort ici, mais il est important de mentionner que les requêtes sur les critères sont désormais obsolètes. Utilisez HQL.

Eskir
la source
1

Je préfère également les requêtes de critères pour les requêtes dynamiques. Mais je préfère hql pour supprimer les requêtes, par exemple si supprimer tous les enregistrements de la table enfant pour l'ID parent 'xyz', cela est facilement réalisé par HQL, mais pour les critères API, nous devons d'abord déclencher n nombre de requêtes de suppression où n est le nombre d'enfants enregistrements de table.

Punit Patel
la source
0

La plupart des réponses ici sont trompeuses et mentionnent qu'elles Criteria Queriessont plus lentes que HQL, ce qui n'est en fait pas le cas.

Si vous approfondissez et effectuez des tests, vous verrez que les requêtes de critères fonctionnent bien mieux que le HQL normal .

Et aussi avec Criteria Query, vous obtenez un contrôle orienté objet qui n'est pas là avec HQL .

Pour plus d'informations, lisez cette réponse ici .

Pritam Banerjee
la source
0

Il y a une autre manière. J'ai fini par créer un analyseur HQL basé sur la syntaxe d'origine hibernate afin qu'il analyse d'abord le HQL, puis il pourrait injecter dynamiquement des paramètres dynamiques ou ajouter automatiquement des filtres communs pour les requêtes HQL. Ça marche super!

Wallace Peng
la source
0

Ce message est assez ancien. La plupart des réponses parlent de critères Hibernate, pas de critères JPA. JPA 2.1 a ajouté CriteriaDelete / CriteriaUpdate et EntityGraph qui contrôle exactement ce qu'il faut récupérer. L'API de critères est meilleure puisque Java est OO. C'est pourquoi JPA est créé. Lorsque JPQL est compilé, il sera traduit en arborescence AST (modèle OO) avant d'être traduit en SQL.

Journée ensoleillée
la source
-3

HQL peut entraîner des problèmes de sécurité comme l'injection SQL.

Emad Aghayi
la source
11
Ces problèmes ne sont pas causés par HQL, mais par le manque de compréhension des pratiques de développement logiciel de base. Je peux également créer du code sujet aux attaques par injection sql avec des critères api.
Jens Schauder
1
C'est comme dire "interroger un SGBDR à partir de Java peut causer des problèmes de sécurité par injection SQL": D
Czar