Come si crea una query distinta in HQL


100

C'è un modo per creare una query distinta in HQL. O utilizzando la parola chiave "distinto" o un altro metodo. Non sono sicuro che distinto sia un lavoro chiave valido per HQL, ma sto cercando l'equivalente HQL della parola chiave SQL "distinto".

Risposte:


124

Ecco uno snippet di hql che usiamo. (I nomi sono stati modificati per proteggere le identità)

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});

Ho usato solo l'ibernazione con MySQL, non sono sicuro di come affrontare il problema di mssql.
Piedi

56

Vale la pena notare che la distinctparola chiave in HQL non si associa direttamente alla distinctparola chiave in SQL.

Se si utilizza la distinctparola chiave in HQL, a volte Hibernate utilizzerà la distinctparola chiave SQL, ma in alcune situazioni utilizzerà un trasformatore di risultati per produrre risultati distinti. Ad esempio, quando utilizzi un outer join come questo:

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

In questo caso non è possibile filtrare i duplicati a livello SQL, quindi Hibernate utilizza a ResultTransformerper filtrare i duplicati dopo che è stata eseguita la query SQL.



16

fai qualcosa di simile la prossima volta

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

 List claz = crit.list();

Non è ottimale: invece di scartare le ripetizioni a livello di database, estrarrà semplicemente i dati dal database alla memoria con le ripetizioni e tutto, quindi scarterà le ripetizioni in seguito; a seconda della frequenza di ripetizione dei dati, ciò può aumentare notevolmente le operazioni di I / O.
Haroldo_OK

9

Puoi anche usarlo Criteria.DISTINCT_ROOT_ENTITYcon la query Hibernate HQL.

Esempio:

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

1
Non è ottimale: invece di scartare le ripetizioni a livello di database, estrarrà semplicemente i dati dal database alla memoria con le ripetizioni e tutto, quindi scarterà le ripetizioni in seguito; a seconda della frequenza di ripetizione dei dati, ciò può aumentare notevolmente le operazioni di I / O.
Haroldo_OK

4

Ho avuto alcuni problemi con i trasformatori di risultati combinati con le query HQL. Quando ho provato

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

non ha funzionato. Ho dovuto trasformare manualmente in questo modo:

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

Con Criteria API i trasformatori hanno funzionato perfettamente.


per arrivare a 10k (:
timmz

3

La mia domanda principale era simile a questa nel modello:

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

E non stavo ancora ottenendo quelli che consideravo risultati "distinti". Erano solo distinti in base a una combinazione di chiavi primarie sul tavolo.

Così nel DaoImplho aggiunto un cambio di riga e ho finito per ottenere il ritorno "distinto" che volevo. Un esempio sarebbe invece di vedere 00 quattro volte, ora lo vedo solo una volta. Ecco il codice che ho aggiunto a 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;       
}

Spero che questo abbia aiutato! Ancora una volta, questo potrebbe funzionare solo se stai seguendo le pratiche di codifica che implementano il servizio, il dao e il tipo di modello del progetto.


2

Supponiamo di avere un'entità cliente mappata alla tabella CUSTOMER_INFORMATION e di voler ottenere un elenco di firstName distinti del cliente. Puoi utilizzare lo snippet di seguito per ottenere lo stesso.

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

Spero possa essere d'aiuto. Quindi qui stiamo usando il gruppo invece di usare una parola chiave distinta.

Inoltre in precedenza ho trovato difficile utilizzare una parola chiave distinta quando voglio applicarla a più colonne. Ad esempio, voglio ottenere un elenco di firstName distinti, lastName quindi group by funzionerebbe semplicemente. In questo caso ho avuto difficoltà a usare distinti.


1

Ho una risposta per Hibernate Query Language per utilizzare i campi distinti. Puoi utilizzare * SELECT DISTINCT (TO_CITY) FROM FLIGHT_ROUTE *. Se usi la query SQL , restituisce String List. Non puoi usarlo come valore di ritorno per Entity Class. Quindi la risposta per risolvere quel tipo di problema è usare HQL con SQL .

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

Da SQL un'istruzione di interrogazione ha ottenuto route_id DISTINCT e l'ingresso in una lista. E la query IN filtra il distinto TO_CITY da IN (List).

Il tipo restituito è il tipo Entity Bean. Quindi puoi farlo in AJAX come AutoComplement .

Che tutto vada bene


1

Puoi tu la parola chiave distinta nel tuo generatore di criteri come questo.

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));

E crea il costruttore del campo nella tua classe del modello.


0

Se è necessario utilizzare una nuova parola chiave per un DTO personalizzato nell'istruzione select e sono necessari elementi distinti , utilizzare nuovo al di fuori di nuovo come segue:

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

0

Puoi semplicemente aggiungere GROUP BY invece di Distinct

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.