web-dev-qa-db-fra.com

Critères d'Hibernate: entités distinctes puis limite

J'ai un critère qui renvoie toutes les données requises par l'application:

Criteria criteria = session.createCriteria(Client.class);
criteria.createAlias("address", "address");
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();

Le problème est que la relation client/adresse est bidirectionnelle: un client a une adresse et une adresse peut appartenir à plusieurs clients.

Je veux récupérer des objets client "uniques" en fonction de leur pk, bien sûr, d'un certain nombre de clients tels qu'ils sont affichés dans un tableau.

Parce que setFirstResult/setMaxResults sont exécutés en premier, je reçois des clients dupliqués dans les limites déjà appliquées. Après (niveau d'application car non utilisé par groupe), hibernate récupère les clients dupliqués, ce qui me laisse moins de clients que le maximum spécifié dans setMaxResults.

Ne peut pas grouper par (groupe de projection) car il ne renverra pas toutes les colonnes requises dans client/adresses, seul le groupe par lequel la requête est groupée.

(En résumé, ma table contient 100 résultats par page, mais après avoir supprimé les doublons, j'ai 98 résultats au lieu de 100 ...), car la limite: LIMIT 0,100 est appliquée AVANT de mettre en hibernation des groupes, alors qu'elle devrait être effectuée APRÈS.

11
kandan

Comme le souligne le fil lié par "Ashish Thukral", la ligne suivante résout ce problème:

criteria.setFetchMode("address.clients", FetchMode.SELECT);

Cela empêche la jointure qui cause le problème. 

Bien sûr, il est possible de supprimer fetch = "join" du fichier de configuration XML mais cette solution n’affecte pas les autres endroits où les beans peuvent être récupérés.

9
kandan

Si vous recherchez un client basé sur l'id, procédez comme suit. En fonction de vos critères, il n'est pas nécessaire de définir la taille maximale et la taille initiale, car elle renvoie toujours un client.

Criteria criteria = getSession().createCriteria(Client.class);
criteria .add(Restrictions.eq("id", yourClientId);
criteria.createAlias("address", "address");
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();

Si vous recherchez une adresse basée sur l'id, comme suit.

Criteria criteria = getSession().createCriteria(Client.class);
criteria.createAlias("address", "address");
criteria .add(Restrictions.eq("address.id", yourAddressId);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();
6
Prabhakaran

Si je comprends bien vos relations, vous aurez une liste de clients dans Adresse et une adresse dans chaque classe d’entité client. Donc, si vous voulez seulement une liste de clients, quel est le problème, les faire passer 

Criteria criteria = session.createCriteria(Client.class);
criteria.setFirstResult(init);
criteria.setMaxResults(max);
List<Client> clients = criteria.list();

Pourquoi créez-vous un alias et utilisez distinct_root_entity? Si vous avez besoin de cette adresse, lorsque vous y accéderez dans votre DAO ou dans ServiceImpl, Hibernate ira quand même la chercher paresseusement pour vous.

Corrigez-moi si je me trompe.

0
Ashish Thukral