¿Cómo se crea una consulta distinta en HQL?

100

¿Hay alguna forma de crear una consulta distinta en HQL? Ya sea usando la palabra clave "distinta" o algún otro método. No estoy seguro de si distinto es un trabajo clave válido para HQL, pero estoy buscando el equivalente en HQL de la palabra clave SQL "distinto".

Mike Pone
fuente

Respuestas:

124

Aquí hay un fragmento de hql que usamos. (Los nombres se han cambiado para proteger las identidades)

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});
Pies
fuente
Solo usé hibernación con MySQL, no estoy seguro de cómo lidiar con el problema de mssql.
Feet
56

Vale la pena señalar que la distinctpalabra clave en HQL no se asigna directamente a la distinctpalabra clave en SQL.

Si usa la distinctpalabra clave en HQL, a veces Hibernate usará la distinctpalabra clave SQL, pero en algunas situaciones usará un transformador de resultados para producir resultados distintos. Por ejemplo, cuando está utilizando una combinación externa como esta:

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

En este caso, no es posible filtrar duplicados a nivel SQL, por lo que Hibernate usa ResultTransformerpara filtrar duplicados después de que se haya realizado la consulta SQL.

Daniel Alexiuc
fuente
1
Respondido aquí: stackoverflow.com/questions/5471819/…
Daniel Alexiuc
16

haz algo como esto la próxima vez

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

 List claz = crit.list();
Miguel
fuente
Eso es subóptimo: en lugar de descartar las repeticiones a nivel de la base de datos, simplemente sacará los datos de la base de datos a la memoria con repeticiones y todo, y luego descartará las repeticiones; dependiendo de la frecuencia con la que se repiten los datos, eso puede aumentar mucho las operaciones de E / S.
Haroldo_OK
9

También puedes usar Criteria.DISTINCT_ROOT_ENTITY con la consulta de Hibernate HQL.

Ejemplo:

Query query = getSession().createQuery("from java_pojo_name");
query.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return query.list();
aadi53
fuente
1
Eso es subóptimo: en lugar de descartar las repeticiones a nivel de la base de datos, simplemente sacará los datos de la base de datos a la memoria con repeticiones y todo, y luego descartará las repeticiones; dependiendo de la frecuencia con la que se repiten los datos, eso puede aumentar mucho las operaciones de E / S.
Haroldo_OK
4

Tuve algunos problemas con los transformadores de resultados combinados con consultas HQL. Cuando lo intenté

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

no funcionó. Tuve que transformar manualmente así:

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

Con Criteria API, los transformadores funcionaron bien.

Tadeusz Kopec
fuente
para llegar a 10k (:
timmz
3

Mi consulta principal se veía así en el modelo:

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

Y todavía no obtenía lo que consideraba resultados "distintos". Eran simplemente distintos basados ​​en una combinación de teclas primarias sobre la mesa.

Entonces DaoImpl, agregué un cambio de una línea y terminé obteniendo el retorno "distinto" que quería. Un ejemplo sería en lugar de ver 00 cuatro veces, ahora solo lo veo una vez. Aquí está el código que agregué 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;       
}

¡Espero que esto haya ayudado! Una vez más, esto solo podría funcionar si sigue prácticas de codificación que implementan el tipo de proyecto de servicio, dao y modelo.

Nathan Mitchell
fuente
2

Suponga que tiene una entidad de cliente asignada a la tabla CUSTOMER_INFORMATION y desea obtener una lista de nombres distintos de cliente. Puede usar el siguiente fragmento para obtener lo mismo.

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

Espero que ayude. Entonces aquí estamos usando group by en lugar de usar una palabra clave distinta.

También anteriormente me resultó difícil usar una palabra clave distinta cuando quiero aplicarla a varias columnas. Por ejemplo, quiero obtener una lista de nombre distinto, apellido y luego agrupar por simplemente funcionaría. Tuve dificultades para usar distinto en este caso.

chammu
fuente
1

Tengo una respuesta para que Hibernate Query Language use campos distintos. Puede usar * SELECT DISTINCT (TO_CITY) FROM FLIGHT_ROUTE *. Si usa una consulta SQL , devuelve String List. No puede usar su valor de retorno por clase de entidad. Entonces, la respuesta para resolver ese tipo de problema es usar 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);

De la declaración de consulta SQL obtuvo DISTINCT ROUTE_ID y la entrada como una lista. Y la consulta IN filtra el TO_CITY distinto de IN (Lista).

El tipo de retorno es el tipo Entity Bean. Entonces puede hacerlo en AJAX como AutoComplement .

Que todo esté bien

San Lin Naing
fuente
1

Puede utilizar la palabra clave distinta en su generador de criterios como este.

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

Y crea el constructor de campo en tu clase de modelo.

Santosh Singh
fuente
0

Si necesita usar una nueva palabra clave para un DTO personalizado en su declaración de selección y necesita elementos distintos , use nuevo fuera de nuevo como sigue:

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

Simplemente puede agregar GROUP BY en lugar de Distinct

@Query(value = "from someTableEntity where entityCode in :entityCode" +
            " group by entityCode, entityName, entityType")
List<someTableEntity > findNameByCode(@Param("entityCode") List<String> entityCode);
Rustem
fuente