Wie erstellen Sie eine eindeutige Abfrage in HQL?


99

Gibt es eine Möglichkeit, eine eindeutige Abfrage in HQL zu erstellen? Entweder mit dem Schlüsselwort "different" oder einer anderen Methode. Ich bin nicht sicher, ob different ein gültiges Schlüsselwerk für HQL ist, aber ich suche nach dem HQL-Äquivalent des SQL-Schlüsselworts "different".

Antworten:


124

Hier ist ein Ausschnitt aus hql, den wir verwenden. (Namen wurden geändert, um Identitäten zu schützen)

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

Ich habe immer nur den Ruhezustand mit MySQL verwendet - ich bin mir nicht sicher, wie ich mit dem MSSQL-Problem umgehen soll.
Füße

56

Es ist erwähnenswert, dass das distinctSchlüsselwort in HQL nicht direkt dem distinctSchlüsselwort in SQL zugeordnet ist.

Wenn Sie das distinctSchlüsselwort in HQL verwenden, verwendet Hibernate manchmal das distinctSQL-Schlüsselwort. In einigen Situationen wird jedoch ein Ergebnistransformator verwendet, um eindeutige Ergebnisse zu erzielen. Zum Beispiel, wenn Sie einen äußeren Join wie folgt verwenden:

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

In diesem Fall ist es nicht möglich, Duplikate auf SQL-Ebene herauszufiltern. Daher verwendet Hibernate a ResultTransformer, um Duplikate zu filtern, nachdem die SQL-Abfrage ausgeführt wurde.



16

Mach das nächste Mal so etwas

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

 List claz = crit.list();

Das ist nicht optimal: Anstatt die Wiederholungen auf Datenbankebene zu verwerfen, werden nur die Daten mit Wiederholungen und allem aus der Datenbank in den Speicher gezogen und anschließend die Wiederholungen verworfen. Abhängig davon, wie oft sich die Daten wiederholen, kann dies die E / A-Vorgänge erheblich steigern.
Haroldo_OK

9

Sie können auch verwenden Criteria.DISTINCT_ROOT_ENTITY mit Hibernate HQL-Abfragen verwenden.

Beispiel:

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

1
Das ist nicht optimal: Anstatt die Wiederholungen auf Datenbankebene zu verwerfen, werden nur die Daten mit Wiederholungen und allem aus der Datenbank in den Speicher gezogen und anschließend die Wiederholungen verworfen. Abhängig davon, wie oft sich die Daten wiederholen, kann dies die E / A-Vorgänge erheblich steigern.
Haroldo_OK

4

Ich hatte einige Probleme mit Ergebnis-Transformatoren in Kombination mit HQL-Abfragen. Als ich es versuchte

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

es hat nicht funktioniert. Ich musste manuell so transformieren:

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

Mit Criteria funktionierten API-Transformatoren einwandfrei.


um auf 10k zu kommen (:
timmz

3

Meine Hauptabfrage sah im Modell folgendermaßen aus:

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

Und ich bekam immer noch nicht das, was ich als "eindeutige" Ergebnisse betrachtete. Sie wurden nur anhand einer Primärschlüsselkombination in der Tabelle unterschieden.

Also DaoImplfügte ich eine einzeilige Änderung hinzu und bekam die "eindeutige" Rendite, die ich wollte. Ein Beispiel wäre, anstatt 00 viermal zu sehen, sehe ich es jetzt nur einmal. Hier ist der Code, den ich hinzugefügt habe 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;       
}

Ich hoffe das hat geholfen! Auch dies funktioniert möglicherweise nur, wenn Sie Codierungspraktiken befolgen, die den Projekttyp Service, Dao und Modell implementieren.


2

Angenommen, Sie haben eine Kundenentität, die der Tabelle CUSTOMER_INFORMATION zugeordnet ist, und möchten eine Liste mit eindeutigen Vornamen des Kunden abrufen. Sie können das folgende Snippet verwenden, um dasselbe zu erhalten.

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

Ich hoffe, es hilft. Hier verwenden wir also group by, anstatt ein bestimmtes Schlüsselwort zu verwenden.

Auch zuvor war es schwierig, ein bestimmtes Schlüsselwort zu verwenden, wenn ich es auf mehrere Spalten anwenden möchte. Zum Beispiel möchte ich eine Liste mit unterschiedlichen Vornamen, Nachnamen und Gruppierungen erhalten, die einfach funktionieren. Ich hatte in diesem Fall Schwierigkeiten, verschiedene zu verwenden.


1

Ich habe eine Antwort für Hibernate Query Language erhalten, um eindeutige Felder zu verwenden. Sie können * SELECT DISTINCT (TO_CITY) FROM FLIGHT_ROUTE * verwenden. Wenn Sie eine SQL- Abfrage verwenden, wird die Zeichenfolgenliste zurückgegeben. Sie können den Rückgabewert nicht nach Entitätsklasse verwenden. Die Antwort zur Lösung dieser Art von Problem ist die Verwendung von HQL mit SQL .

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

Aus SQL Abfrageanweisung wurde DISTINCT ROUTE_ID abgerufen und als Liste eingegeben. Und die IN-Abfrage filtert die unterschiedliche TO_CITY von IN (Liste).

Der Rückgabetyp ist der Entity Bean-Typ. So können Sie es in AJAX wie AutoComplement .

Möge alles in Ordnung sein


1

Sie können das eindeutige Schlüsselwort in Ihrem Kriterien-Builder wie folgt eingeben.

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

Und erstellen Sie den Feldkonstruktor in Ihrer Modellklasse.


0

Wenn Sie ein neues Schlüsselwort für ein benutzerdefiniertes DTO in Ihrer select-Anweisung verwenden müssen und unterschiedliche Elemente benötigen , verwenden Sie new außerhalb von new wie folgt:

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

0

Sie können einfach GROUP BY anstelle von Distinct hinzufügen

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.