Jak utworzyć odrębne zapytanie w HQL

100

Czy istnieje sposób na utworzenie Distinct zapytania w HQL. Albo za pomocą słowa kluczowego „wyraźny”, albo w inny sposób. Nie jestem pewien, czy odrębny jest prawidłowym kluczem do HQL, ale szukam odpowiednika HQL słowa kluczowego SQL „wyraźny”.

Mike Pone
źródło

Odpowiedzi:

124

Oto fragment kodu hql, którego używamy. (Nazwy zostały zmienione w celu ochrony tożsamości)

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});
Stopy
źródło
Używałem hibernacji tylko z MySQL - nie jestem pewien, jak poradzić sobie z problemem mssql.
Stopy
56

Warto zauważyć, że distinctsłowo kluczowe w HQL nie jest odwzorowywane bezpośrednio na distinctsłowo kluczowe w SQL.

Jeśli użyjesz distinctsłowa kluczowego w HQL, to czasami Hibernate użyje distinctsłowa kluczowego SQL, ale w niektórych sytuacjach użyje transformatora wyników, aby uzyskać różne wyniki. Na przykład, gdy używasz sprzężenia zewnętrznego takiego:

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

W tym przypadku nie jest możliwe odfiltrowanie duplikatów na poziomie SQL, dlatego Hibernate używa ResultTransformerdo odfiltrowania duplikatów po wykonaniu zapytania SQL.

Daniel Alexiuc
źródło
1
Odpowiedział tutaj: stackoverflow.com/questions/5471819/ ...
Daniel Alexiuc
16

zrób coś takiego następnym razem

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

 List claz = crit.list();
Michael
źródło
To nieoptymalne: zamiast odrzucać powtórzenia na poziomie bazy danych, po prostu pobierze dane z bazy danych do pamięci z powtórzeniami i wszystkim, a następnie odrzuci powtórzenia; w zależności od tego, jak często dane się powtarzają, może to znacznie zwiększyć liczbę operacji we / wy.
Haroldo_OK
9

Możesz również używać Criteria.DISTINCT_ROOT_ENTITYz zapytaniem Hibernate HQL.

Przykład:

Query query = getSession().createQuery("from java_pojo_name");
query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return query.list();
aadi53
źródło
1
To nieoptymalne: zamiast odrzucać powtórzenia na poziomie bazy danych, po prostu pobierze dane z bazy danych do pamięci z powtórzeniami i wszystkim, a następnie odrzuci powtórzenia; w zależności od tego, jak często dane się powtarzają, może to znacznie zwiększyć liczbę operacji we / wy.
Haroldo_OK
4

Miałem problemy z transformatorami wyników w połączeniu z zapytaniami HQL. Kiedy próbowałem

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

to nie zadziałało. Musiałem przekształcić ręcznie w ten sposób:

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

Z Criteria API transformatory działały dobrze.

Tadeusz Kopeć
źródło
dostać się do 10k (:
timmz
3

Moje główne zapytanie wyglądało w modelu tak:

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

I nadal nie uzyskiwałem tego, co uważałem za „wyraźne” wyniki. Były po prostu różne na podstawie kombinacji klawiszy podstawowych na stole.

Więc DaoImpldodałem zmianę o jedną linię i skończyło się na uzyskaniu "wyraźnego" zwrotu, którego chciałem. Przykładem może być to, że zamiast czterokrotnie zobaczyć 00, teraz widzę to tylko raz. Oto kod, który dodałem do 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;       
}

Mam nadzieję, że to pomogło! Po raz kolejny może to działać tylko wtedy, gdy przestrzegasz praktyk kodowania, które implementują usługę, dao i model typu projektu.

Nathan Mitchell
źródło
2

Załóżmy, że masz jednostkę klienta zmapowaną do tabeli CUSTOMER_INFORMATION i chcesz uzyskać listę odrębnych firstName klienta. Możesz użyć poniższego fragmentu, aby uzyskać to samo.

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

Mam nadzieję, że to pomoże. Więc tutaj używamy grupy by zamiast używać słowa kluczowego odrębnego.

Również wcześniej było mi trudno użyć odrębnego słowa kluczowego, gdy chcę go zastosować do wielu kolumn. Na przykład chcę uzyskać listę odrębnych firstName, lastName, a następnie grupowanie według po prostu zadziała. W tym przypadku miałem trudności z użyciem odrębnego.

chammu
źródło
1

Mam odpowiedź na Hibernate Query Language, aby używać odrębnych pól. Możesz użyć * SELECT DISTINCT (TO_CITY) FROM FLIGHT_ROUTE *. Jeśli używasz zapytania SQL , zwraca listę ciągów. Nie można jej użyć zwracanej wartości przez klasę jednostki. Zatem odpowiedzią na ten typ problemu jest użycie języka HQL z SQL .

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

Z SQL zapytania otrzymano DISTINCT ROUTE_ID i wprowadzono jako listę. A zapytanie IN filtruje odrębne TO_CITY z IN (Lista).

Typ zwrotu to typ Entity Bean. Więc możesz to zrobić w AJAX, takim jak AutoComplement .

Może wszystko będzie w porządku

San Lin Naing
źródło
1

Możesz w ten sposób określić odrębne słowo kluczowe w konstruktorze kryteriów.

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

I utwórz konstruktora pola w swojej klasie modelu.

Santosh Singh
źródło
0

Jeśli potrzebujesz nowego słowa kluczowego dla niestandardowego DTO w instrukcji select i potrzebujesz odrębnych elementów , użyj nowego poza nowym, jak poniżej:

select distinct new com.org.AssetDTO(a.id, a.address, a.status) from Asset as a where ...
Manish Sharma
źródło
0

Możesz po prostu dodać GROUP BY zamiast Distinct

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
Rustem
źródło