¿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".

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

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.



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

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

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.


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.


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.


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


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.


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 ...

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);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.