Comment créer une requête distincte dans HQL


100

Existe-t-il un moyen de créer une requête distincte dans HQL. Soit en utilisant le mot-clé «distinct» ou une autre méthode. Je ne sais pas si distinct est un keywork valide pour HQL, mais je recherche l'équivalent HQL du mot-clé SQL "distinct".

Réponses:


124

Voici un extrait de hql que nous utilisons. (Les noms ont été modifiés pour protéger les identités)

String queryString = "select distinct f from Foo f inner join foo.bars as b" +
                " where f.creationDate >= ? and f.creationDate < ? and b.bar = ?";
        return getHibernateTemplate().find(queryString, new Object[] {startDate, endDate, bar});

Je n'ai jamais utilisé la mise en veille prolongée avec MySQL - je ne sais pas comment gérer le problème mssql.
Pieds

56

Il est à noter que le distinctmot - clé en HQL ne correspond pas directement au distinctmot - clé en SQL.

Si vous utilisez le distinctmot - clé dans HQL, alors Hibernate utilisera parfois le distinctmot-clé SQL, mais dans certaines situations, il utilisera un transformateur de résultat pour produire des résultats distincts. Par exemple, lorsque vous utilisez une jointure externe comme celle-ci:

select distinct o from Order o left join fetch o.lineItems

Il n'est pas possible de filtrer les doublons au niveau SQL dans ce cas, donc Hibernate utilise a ResultTransformerpour filtrer les doublons une fois la requête SQL effectuée.



16

faire quelque chose comme ça la prochaine fois

 Criteria crit = (Criteria) session.
                  createCriteria(SomeClass.class).
                  setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);

 List claz = crit.list();

C'est sous-optimal: au lieu de rejeter les répétitions au niveau de la base de données, il va simplement extraire les données de la base de données vers la mémoire avec des répétitions et tout, puis rejeter les répétitions par la suite; en fonction de la fréquence de répétition des données, cela peut augmenter considérablement les opérations d'E / S.
Haroldo_OK

9

Vous pouvez également utiliser Criteria.DISTINCT_ROOT_ENTITYavec la requête Hibernate HQL.

Exemple:

Query query = getSession().createQuery("from java_pojo_name");
query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return query.list();

1
C'est sous-optimal: au lieu de rejeter les répétitions au niveau de la base de données, il va simplement extraire les données de la base de données vers la mémoire avec des répétitions et tout, puis rejeter les répétitions par la suite; en fonction de la fréquence de répétition des données, cela peut augmenter considérablement les opérations d'E / S.
Haroldo_OK

4

J'ai eu quelques problèmes avec les transformateurs de résultats combinés aux requêtes HQL. Quand j'ai essayé

final ResultTransformer trans = new DistinctRootEntityResultTransformer();
qry.setResultTransformer(trans);

ça n'a pas marché. J'ai dû transformer manuellement comme ceci:

final List found = trans.transformList(qry.list());

Avec Criteria, les transformateurs fonctionnaient très bien.


pour arriver à 10
km

3

Ma requête principale ressemblait à ceci dans le modèle:

@NamedQuery(name = "getAllCentralFinancialAgencyAccountCd", 
    query = "select distinct i from CentralFinancialAgencyAccountCd i")

Et je n'obtenais toujours pas ce que je considérais comme des résultats «distincts». Ils étaient simplement distincts en fonction d'une combinaison de clés primaires sur la table.

Ainsi , dans le DaoImplj'ai ajouté un changement d' une ligne et a fini par obtenir le retour , je voulais « distinct ». Un exemple serait au lieu de voir 00 quatre fois, je le vois maintenant une seule fois. Voici le code que j'ai ajouté au DaoImpl:

@SuppressWarnings("unchecked")
public List<CacheModelBase> getAllCodes() {

    Session session = (Session) entityManager.getDelegate();
    org.hibernate.Query q = session.getNamedQuery("getAllCentralFinancialAgencyAccountCd");
    q.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); // This is the one line I had to add to make it do a more distinct query.
    List<CacheModelBase> codes;
    codes = q.list();
    return codes;       
}

J'espère que cela a aidé! Encore une fois, cela peut ne fonctionner que si vous suivez des pratiques de codage qui implémentent le type de projet service, DAO et modèle.


2

Supposons que vous ayez une entité client mappée à la table CUSTOMER_INFORMATION et que vous souhaitiez obtenir la liste des prénoms distincts du client. Vous pouvez utiliser l'extrait ci-dessous pour obtenir la même chose.

Query distinctFirstName = session.createQuery("select ci.firstName from Customer ci group by ci.firstName");
Object [] firstNamesRows = distinctFirstName.list();

J'espère que cela aide. Nous utilisons donc ici group by au lieu d'utiliser un mot-clé distinct.

Aussi, auparavant, j'ai trouvé difficile d'utiliser un mot-clé distinct lorsque je veux l'appliquer à plusieurs colonnes. Par exemple, je veux obtenir une liste de firstName distincts, lastName puis group by fonctionnerait simplement. J'ai eu du mal à utiliser distinct dans ce cas.


1

J'ai une réponse pour Hibernate Query Language pour utiliser des champs distincts. Vous pouvez utiliser * SELECT DISTINCT (TO_CITY) FROM FLIGHT_ROUTE *. Si vous utilisez une requête SQL , elle renvoie une liste de chaînes. Vous ne pouvez pas l'utiliser comme valeur de retour par classe d'entité. La réponse pour résoudre ce type de problème est donc d'utiliser HQL avec SQL .

FROM FLIGHT_ROUTE F WHERE F.ROUTE_ID IN (SELECT SF.ROUTE_ID FROM FLIGHT_ROUTE SF GROUP BY SF.TO_CITY);

À partir de l' instruction de requête SQL , il a obtenu DISTINCT ROUTE_ID et entré sous forme de liste. Et la requête IN filtre la TO_CITY distincte de IN (List).

Le type de retour est le type Entity Bean. Vous pouvez donc le faire dans AJAX, comme le complément automatique .

Que tout va bien


1

Vous pouvez vous le mot-clé distinct dans votre générateur de critères comme celui-ci.

CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Orders> query = builder.createQuery(Orders.class);
Root<Orders> root = query.from(Orders.class);
query.distinct(true).multiselect(root.get("cust_email").as(String.class));

Et créez le constructeur de champ dans votre classe de modèle.


0

Si vous avez besoin d'utiliser un nouveau mot-clé pour un DTO personnalisé dans votre instruction select et que vous avez besoin d' éléments distincts , utilisez new en dehors de new comme suit:

select distinct new com.org.AssetDTO(a.id, a.address, a.status) from Asset as a where ...

0

Vous pouvez simplement ajouter GROUP BY au lieu de Distinct

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.